home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume23 / trn / part11 < prev    next >
Encoding:
Text File  |  1991-08-22  |  64.4 KB  |  2,560 lines

  1. This is a new archive version of TRN at patchlevel 3.
  2. The original posting took up Volume23, issues 60 to 73, with
  3. various problems.  These files replace those issues.
  4.  
  5. #! /bin/sh
  6. # This is a shell archive.  Remove anything before this line, then feed it
  7. # into a shell via "sh file" or similar.  To overwrite existing files,
  8. # type "sh file -c".
  9. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  10. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  11. # Contents:  bits.h init.c mthreads.1 ngdata.c ngstuff.c term.h util.c
  12. # Wrapped by rsalz@litchi.bbn.com on Fri Aug 23 16:39:01 1991
  13. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  14. echo If this archive is complete, you will see the following message:
  15. echo '          "shar: End of archive 11 (of 14)."'
  16. if test -f 'bits.h' -a "${1}" != "-c" ; then 
  17.   echo shar: Will not clobber existing file \"'bits.h'\"
  18. else
  19.   echo shar: Extracting \"'bits.h'\" \(2440 characters\)
  20.   sed "s/^X//" >'bits.h' <<'END_OF_FILE'
  21. X/* $Header: bits.h,v 4.3.3.2 91/01/16 02:29:50 davison Trn $
  22. X *
  23. X * $Log:    bits.h,v $
  24. X * Revision 4.3.3.2  91/01/16  02:29:50  davison
  25. X * Added optional prototyping.
  26. X * 
  27. X * Revision 4.3.3.1  90/06/20  22:36:35  davison
  28. X * Initial Trn Release
  29. X * 
  30. X * Revision 4.3.2.1  90/11/22  15:46:42  sob
  31. X * Made changes to make pickly preprocessors happier.
  32. X * 
  33. X * Revision 4.3.1.2  86/11/03  09:49:58  lwall
  34. X * Added firstbit variable.
  35. X * 
  36. X * Revision 4.3.1.1  85/05/10  11:31:52  lwall
  37. X * Branch for patches.
  38. X * 
  39. X * Revision 4.3  85/05/01  11:36:39  lwall
  40. X * Baseline for release with 4.3bsd.
  41. X * 
  42. X */
  43. X
  44. XEXT char *ctlarea INIT(Nullch);    /* one bit for each article in current newsgroup */
  45. X            /* with the following interpretation: */
  46. X            /*    0 => unread  */
  47. X            /*    1 => read    */
  48. X
  49. X/* if subscripting is faster than shifting on your machine, define this */
  50. X#undef USESUBSCRIPT
  51. X#ifdef USESUBSCRIPT
  52. XEXT char powerof2[] INIT({1,2,4,8,16,32,64,128});
  53. X#define pow2(x) powerof2[x]
  54. X#else
  55. X#define pow2(x) (1 << (x))
  56. X#endif
  57. X
  58. X#ifdef lint
  59. XEXT bool nonesuch INIT(FALSE);
  60. X#define ctl_set(a)
  61. X#define ctl_clear(a)
  62. X#define ctl_read(a) nonesuch
  63. X#define was_read(a) nonesuch
  64. X#else
  65. X#define ctl_set(a) (ctlarea[(OFFSET(a)) / BITSPERBYTE] |= pow2((OFFSET(a)) % BITSPERBYTE))
  66. X#define ctl_clear(a) (ctlarea[(OFFSET(a)) / BITSPERBYTE] &= ~pow2((OFFSET(a)) % BITSPERBYTE))
  67. X#define ctl_read(a) ((ctlarea[(OFFSET(a)) / BITSPERBYTE] & pow2((OFFSET(a)) % BITSPERBYTE)) != 0)
  68. X
  69. X#define was_read(a) ((a)<firstbit || ctl_read(a))
  70. X#endif /* lint */
  71. X
  72. XEXT ART_NUM absfirst INIT(0);    /* 1st real article in current newsgroup */
  73. XEXT ART_NUM firstart INIT(0);    /* minimum unread article number in newsgroup */
  74. XEXT ART_NUM firstbit INIT(0);    /* minimum valid bit, usually == firstart */
  75. XEXT ART_NUM lastart INIT(0);    /* maximum article number in newsgroup */
  76. X
  77. X#ifdef DELAYMARK
  78. XEXT FILE *dmfp INIT(Nullfp);
  79. XEXT char *dmname INIT(Nullch);
  80. XEXT int dmcount INIT(0);
  81. X#endif
  82. X
  83. Xvoid    bits_init ANSI((void));
  84. Xvoid    checkpoint_rc ANSI((void));
  85. Xvoid    restore_ng ANSI((void));
  86. Xvoid    onemore ANSI((ART_NUM));
  87. Xvoid    oneless ANSI((ART_NUM));
  88. Xvoid    unmark_as_read ANSI((void));
  89. X#ifdef USETHREADS
  90. Xvoid    set_read ANSI((ART_NUM,int));
  91. Xvoid    set_unread ANSI((ART_NUM,int));
  92. X#endif
  93. Xvoid    delay_unmark ANSI((ART_NUM));
  94. Xvoid    mark_as_read ANSI((void));
  95. Xvoid    check_first ANSI((ART_NUM));
  96. X#ifdef DELAYMARK
  97. X    void    yankback ANSI((void));
  98. X#endif
  99. Xint    chase_xrefs ANSI((ART_NUM,int));
  100. Xint    initctl ANSI((void));
  101. Xvoid    grow_ctl ANSI((ART_NUM));
  102. END_OF_FILE
  103.   if test 2440 -ne `wc -c <'bits.h'`; then
  104.     echo shar: \"'bits.h'\" unpacked with wrong size!
  105.   fi
  106.   # end of 'bits.h'
  107. fi
  108. if test -f 'init.c' -a "${1}" != "-c" ; then 
  109.   echo shar: Will not clobber existing file \"'init.c'\"
  110. else
  111.   echo shar: Extracting \"'init.c'\" \(8905 characters\)
  112.   sed "s/^X//" >'init.c' <<'END_OF_FILE'
  113. X/* $Header: init.c,v 4.3.3.2 91/01/16 02:43:39 davison Trn $
  114. X *
  115. X * $Log:    init.c,v $
  116. X * Revision 4.3.3.2  91/01/16  02:43:39  davison
  117. X * Integrated rn patches 48-54.  Twiddled 'rn' to 'trn'.
  118. X * 
  119. X * Revision 4.3.3.1  90/06/20  22:37:39  davison
  120. X * Initial Trn Release
  121. X * 
  122. X * Revision 4.3.2.8  90/11/22  13:51:39  sob
  123. X * Removed some cruft trailing the #endif directive to make more compilers
  124. X * happy.
  125. X * 
  126. X * Revision 4.3.2.7  90/10/30  22:42:23  sob
  127. X * Used fileno() instead of _file to increase portability.
  128. X * 
  129. X * Revision 4.3.2.6  90/05/08  22:05:55  sob
  130. X * Added quick startup (-q) flag.
  131. X * 
  132. X * Revision 4.3.2.5  90/05/04  23:10:01  sob
  133. X * Fix for exiting "second" rn such that tty will be left in correct state.
  134. X * Provided by glenn@mathcs.emory.edu
  135. X * 
  136. X * Revision 4.3.2.4  90/03/22  23:04:32  sob
  137. X * Fixes provided by Wayne Davison <drivax!davison>
  138. X * 
  139. X * Revision 4.3.2.3  90/03/17  21:34:04  sob
  140. X * Cleaned up a bit.
  141. X * 
  142. X * Revision 4.3.2.2  89/11/08  01:17:48  sob
  143. X * Added changes to insure that this will compile for RN or RRN with no
  144. X * changes to the source code.
  145. X * 
  146. X * Revision 4.3.2.1  89/11/06  00:39:14  sob
  147. X * Added RRN support from NNTP 1.5
  148. X * 
  149. X * Revision 4.3.1.4  86/09/05  14:24:02  lwall
  150. X * Removed net.announce dependency.
  151. X * 
  152. X * Revision 4.3.1.3  85/07/23  18:08:36  lwall
  153. X * Fixed up NOLINEBUF option to work.
  154. X * 
  155. X * Revision 4.3.1.2  85/05/21  14:22:46  lwall
  156. X * Sped up "rn -c" by avoiding unnecessary initialization.
  157. X * 
  158. X * Revision 4.3.1.1  85/05/10  11:33:39  lwall
  159. X * Branch for patches.
  160. X * 
  161. X * Revision 4.3  85/05/01  16:16:13  lwall
  162. X * Baseline for release with 4.3bsd.
  163. X * 
  164. X */
  165. X
  166. X#include "EXTERN.h"
  167. X#include "common.h"
  168. X#include "util.h"
  169. X#include "final.h"
  170. X#include "term.h"
  171. X#include "last.h"
  172. X#include "rn.h"
  173. X#include "rcstuff.h"
  174. X#include "ngdata.h"
  175. X#include "only.h"
  176. X#include "intrp.h"
  177. X#include "addng.h"
  178. X#include "sw.h"
  179. X#include "art.h"
  180. X#include "artsrch.h"
  181. X#include "artio.h"
  182. X#include "backpage.h"
  183. X#include "bits.h"
  184. X#include "cheat.h"
  185. X#include "head.h"
  186. X#include "help.h"
  187. X#include "kfile.h"
  188. X#include "ngsrch.h"
  189. X#include "ngstuff.h"
  190. X#include "rcln.h"
  191. X#include "respond.h"
  192. X#ifdef SERVER
  193. X#include "server.h"
  194. X#endif
  195. X#ifdef USETHREADS
  196. X#include "rthreads.h"
  197. X#endif
  198. X#include "ng.h"
  199. X#include "INTERN.h"
  200. X#include "init.h"
  201. X
  202. Xbool
  203. Xinitialize(argc,argv)
  204. Xint argc;
  205. Xchar *argv[];
  206. X{
  207. X    char *tcbuf;
  208. X    register bool foundany = FALSE;
  209. X    long time();
  210. X#ifdef SERVER
  211. X    char *server;
  212. X    int response;
  213. X#endif
  214. X#ifdef NOLINEBUF
  215. X    static char std_out_buf[BUFSIZ];    /* must be static or malloced */
  216. X
  217. X    setbuf(stdout, std_out_buf);
  218. X#endif
  219. X
  220. X    tcbuf = safemalloc(1024);        /* make temp buffer for termcap and */
  221. X                    /* other initialization stuff */
  222. X    
  223. X    /* init terminal */
  224. X    
  225. X    term_init();            /* must precede sw_init() so that */
  226. X                    /* ospeed is set for baud-rate */
  227. X                    /* switches.  Actually terminal */
  228. X                    /* mode setting is in term_set() */
  229. X
  230. X    /* we have to know rnlib to look up global switches in %X/INIT */
  231. X
  232. X    lib = savestr(filexp(LIB));
  233. X    rnlib = savestr(filexp(RNLIB));
  234. X
  235. X    /* decode switches */
  236. X
  237. X    sw_init(argc,argv,&tcbuf);          /* must not do % interps! */
  238. X                    /* (but may mung environment) */
  239. X
  240. X    /* init signals, status flags */
  241. X
  242. X    final_init();
  243. X    
  244. X    /* start up file expansion and the % interpreter */
  245. X
  246. X    intrp_init(tcbuf);
  247. X    
  248. X    /* now make sure we have a current working directory */
  249. X
  250. X    if (!checkflag)
  251. X    cwd_check();
  252. X    
  253. X    /* now that we know where to save things, cd to news directory */
  254. X
  255. X    if (chdir(spool)) {
  256. X    printf(nocd,spool) FLUSH;
  257. X    finalize(1);
  258. X    }
  259. X
  260. X    /* if we aren't just checking, turn off echo */
  261. X
  262. X    if (!checkflag)
  263. X    term_set(tcbuf);
  264. X
  265. X    /* get info on last rn run, if any */
  266. X
  267. X    if (!checkflag)
  268. X    last_init(tcbuf);
  269. X
  270. X    free(tcbuf);            /* recover 1024 bytes */
  271. X
  272. X    /* make sure we are the sole possessors of .newsrc */
  273. X
  274. X    if (!checkflag)
  275. X    lock_check();
  276. X
  277. X    /* check for news news */
  278. X
  279. X    if (!checkflag)
  280. X    newsnews_check();
  281. X
  282. X#ifdef SERVER
  283. X
  284. X    /* open connection to server if appropriate */
  285. X
  286. X    server = getserverbyfile(SERVER_FILE);
  287. X    if (server == NULL) {
  288. X    fprintf(stderr, "Can't get the name of the news server from %s\n",
  289. X        SERVER_FILE);
  290. X    fprintf(stderr,
  291. X      "Either fix this file, or put NNTPSERVER in your environment.\n");
  292. X    finalize(1);
  293. X    }
  294. X
  295. X    response = server_init(server);
  296. X    if (response < 0) {
  297. X    fprintf(stderr,
  298. X        "Couldn't connect to %s news server, try again later.\n",
  299. X        server);
  300. X    finalize(1);
  301. X    }
  302. X
  303. X    if (handle_server_response(response, server) < 0)
  304. X    finalize(1);
  305. X
  306. X#endif
  307. X
  308. X    /* open active file, etc. */
  309. X
  310. X    ngdata_init();
  311. X
  312. X    /* now read in the .newsrc file */
  313. X
  314. X    foundany = rcstuff_init();
  315. X
  316. X    /* it looks like we will actually read something, so init everything */
  317. X
  318. X    addng_init();
  319. X    art_init();
  320. X    artio_init();
  321. X    artsrch_init();
  322. X    backpage_init();
  323. X    bits_init();
  324. X    cheat_init();
  325. X    head_init();
  326. X    help_init();
  327. X    kfile_init();
  328. X    ng_init();
  329. X    ngsrch_init();
  330. X    ngstuff_init();
  331. X    only_init();
  332. X    rcln_init();
  333. X    respond_init();
  334. X    rn_init();
  335. X    search_init();
  336. X#ifdef USETHREADS
  337. X    thread_init();
  338. X#endif
  339. X    util_init();
  340. X
  341. X#ifdef FINDNEWNG
  342. X/*  fstat(actfp->_file,&filestat);    ... does not work on Apollos */
  343. X    fstat(fileno(actfp),&filestat);    /* did active file grow? */
  344. X    /*
  345. X     * Skip this check if the -q flag was given.
  346. X     */
  347. X    
  348. X    if (!quickstart && filestat.st_size != lastactsiz) {
  349. X    long actsiz = filestat.st_size;    /* remember new size */
  350. X    NG_NUM oldnext = nextrcline;    /* remember # lines in newsrc */
  351. X#ifdef FASTNEW
  352. X    bool munged = writesoft || !lastactsiz;
  353. X                    /* bad soft ptrs -> edited active */
  354. X#else
  355. X    bool munged = TRUE;        /* just assume .newsrc munged */
  356. X#endif
  357. X
  358. X#ifdef VERBOSE
  359. X    IF(verbose)
  360. X        fputs("\nChecking active list for new newsgroups...\n",stdout)
  361. X          FLUSH;
  362. X    ELSE
  363. X#endif
  364. X#ifdef TERSE
  365. X        fputs("\nNew newsgroups:\n",stdout) FLUSH;
  366. X#endif
  367. X#ifdef FASTNEW
  368. X    if (!munged) {            /* maybe just do tail of file? */
  369. X        fseek(actfp,lastactsiz-NL_SIZE,0);
  370. X        fgets(buf,LBUFLEN,actfp);
  371. X        munged = (*buf != '\n');
  372. X        if (!munged)
  373. X        munged = newlist(munged,FALSE);
  374. X    }
  375. X#endif
  376. X    if (munged) {            /* must we scan entire file? */
  377. X        fseek(actfp,0L,0);        /* rewind active file */
  378. X        newlist(munged,FALSE);      /* sure hope they use hashing... */
  379. X    }
  380. X    lastactsiz = actsiz;        /* remember for .rnlast */
  381. X    if (nextrcline != oldnext) {    /* did we add any new groups? */
  382. X        foundany = TRUE;        /* let main() know */
  383. X        starthere = 0;              /* and start ng scan from the top */
  384. X    }
  385. X    }
  386. X#endif
  387. X    time(&lasttime);            /* remember when we inited-- */
  388. X                    /* ends up back in .rnlast */
  389. X    writelast();                       /* in fact, put it there now */
  390. X    
  391. X#ifdef FINDNEWNG
  392. X# ifdef ONLY
  393. X    if (maxngtodo)            /* patterns on command line? */
  394. X    foundany |= scanactive();
  395. X# endif
  396. X#endif
  397. X
  398. X    return foundany;
  399. X}
  400. X
  401. X/* make sure there is no rn out there already */
  402. X
  403. Xvoid
  404. Xlock_check()
  405. X{
  406. X    lockname = savestr(filexp(LOCKNAME));
  407. X    if (!checkflag) {
  408. X    tmpfp = fopen(lockname,"r");
  409. X    if (tmpfp != Nullfp) {
  410. X        int processnum;
  411. X    
  412. X        fgets(buf,LBUFLEN,tmpfp);
  413. X        fclose(tmpfp);
  414. X        processnum = atoi(buf);
  415. X#ifdef VERBOSE
  416. X        IF(verbose)
  417. X        printf("You seem to have left a trn running, process %d.\n",
  418. X            processnum) FLUSH;
  419. X        ELSE
  420. X#endif
  421. X#ifdef TERSE
  422. X        printf("Trn left running, #%d.\n", processnum) FLUSH;
  423. X#endif
  424. X        if (kill(processnum, SIGEMT)) {
  425. X                    /* does process not exist? */
  426. X                    /* (rn ignores SIGEMT) */
  427. X        sleep(2);
  428. X#ifdef VERBOSE
  429. X        IF(verbose)
  430. X            fputs("\n\
  431. XThat process does not seem to exist anymore.  The count of read articles\n\
  432. Xmay be incorrect in the last newsgroup accessed by that other (defunct)\n\
  433. Xprocess.\n\n",stdout) FLUSH;
  434. X        ELSE
  435. X#endif
  436. X#ifdef TERSE
  437. X            fputs("\nProcess crashed.\n",stdout) FLUSH;
  438. X#endif
  439. X        if (*lastngname) {
  440. X#ifdef VERBOSE
  441. X            IF(verbose)
  442. X            printf("(The last newsgroup accessed was %s.)\n\n",
  443. X            lastngname) FLUSH;
  444. X            ELSE
  445. X#endif
  446. X#ifdef TERSE
  447. X            printf("(In %s.)\n\n",lastngname) FLUSH;
  448. X#endif
  449. X        }
  450. X        get_anything();
  451. X        putchar('\n') FLUSH;
  452. X        }
  453. X        else {
  454. X#ifdef VERBOSE
  455. X        IF(verbose)
  456. X            fputs("\n\
  457. XYou may not have two copies of [t]rn running simultaneously.  Goodbye.\n\
  458. X",stdout) FLUSH;
  459. X        ELSE
  460. X#endif
  461. X#ifdef TERSE
  462. X            fputs("\nCan't start another.\n",stdout) FLUSH;
  463. X#endif
  464. X               if (bizarre)
  465. X                 resetty();
  466. X        exit(0);
  467. X        }
  468. X    }
  469. X    tmpfp = fopen(lockname,"w");
  470. X    if (tmpfp == Nullfp) {
  471. X        printf(cantcreate,lockname) FLUSH;
  472. X        sig_catcher(0);
  473. X    }
  474. X    fprintf(tmpfp,"%d\n",getpid());
  475. X    fclose(tmpfp);
  476. X    }
  477. X}
  478. X
  479. Xvoid
  480. Xnewsnews_check()
  481. X{
  482. X    char *newsnewsname = filexp(NEWSNEWSNAME);
  483. X
  484. X    if ((tmpfp = fopen(newsnewsname,"r")) != Nullfp) {
  485. X/*    fstat(tmpfp->_file,&filestat);   .... does not work on Apollos */
  486. X    fstat(fileno(tmpfp),&filestat);
  487. X    if (filestat.st_mtime > lasttime) {
  488. X        while (fgets(buf,sizeof(buf),tmpfp) != Nullch)
  489. X        fputs(buf,stdout) FLUSH;
  490. X        get_anything();
  491. X        putchar('\n') FLUSH;
  492. X    }
  493. X    fclose(tmpfp);
  494. X    }
  495. X}
  496. END_OF_FILE
  497.   if test 8905 -ne `wc -c <'init.c'`; then
  498.     echo shar: \"'init.c'\" unpacked with wrong size!
  499.   fi
  500.   # end of 'init.c'
  501. fi
  502. if test -f 'mthreads.1' -a "${1}" != "-c" ; then 
  503.   echo shar: Will not clobber existing file \"'mthreads.1'\"
  504. else
  505.   echo shar: Extracting \"'mthreads.1'\" \(9578 characters\)
  506.   sed "s/^X//" >'mthreads.1' <<'END_OF_FILE'
  507. X''' $Header: mthreads.1,v 4.3.3.3 91/01/18 19:27:39 davison Trn $
  508. X''' 
  509. X''' $Log:    mthreads.1,v $
  510. X''' Revision 4.3.3.3  91/01/18  19:27:39  davison
  511. X''' Added commands -s and -z.
  512. X''' 
  513. X''' Revision 4.3.3.2  90/08/20  16:42:32  davison
  514. X''' Document new command-line interface.
  515. X''' 
  516. X''' Revision 4.3.3.1  90/07/21  20:03:37  davison
  517. X''' Initial Trn Release
  518. X''' 
  519. X''' 
  520. X.de Sh
  521. X.br
  522. X.ne 5
  523. X.PP
  524. X\fB\\$1\fR
  525. X.PP
  526. X..
  527. X.de Sp
  528. X.if t .sp .5v
  529. X.if n .sp
  530. X..
  531. X.de Ip
  532. X.br
  533. X.ie \\n.$>=3 .ne \\$3
  534. X.el .ne 3
  535. X.IP "\\$1" \\$2
  536. X..
  537. X'''
  538. X'''     Set up \*(-- to give an unbreakable dash;
  539. X'''     string Tr holds user defined translation string.
  540. X'''     Bell System Logo is used as a dummy character.
  541. X'''
  542. X.tr \(bs-|\(bv\*(Tr
  543. X.ie n \{\
  544. X.ds -- \(bs-
  545. X.if (\n(.H=4u)&(1m=24u) .ds -- \(bs\h'-12u'\(bs\h'-12u'-\" diablo 10 pitch
  546. X.if (\n(.H=4u)&(1m=20u) .ds -- \(bs\h'-12u'\(bs\h'-8u'-\" diablo 12 pitch
  547. X.ds L" ""
  548. X.ds R" ""
  549. X.ds L' '
  550. X.ds R' '
  551. X'br\}
  552. X.el\{\
  553. X.ds -- \(em\|
  554. X.tr \*(Tr
  555. X.ds L" ``
  556. X.ds R" ''
  557. X.ds L' `
  558. X.ds R' '
  559. X'br\}
  560. X.TH MTHREADS 1 LOCAL
  561. X.UC 6
  562. X.SH NAME
  563. Xmthreads - threaded database manager for trn
  564. X.SH SYNOPSIS
  565. X.B mthreads [-d[MM]] [-e[HHMM]] [-aDfknv] [hierarchy_list]
  566. X.SH DESCRIPTION
  567. X.I Mthreads
  568. Xmanages the thread files that are used by the
  569. X.IR trn (1)
  570. Xnewsreader.
  571. X\*(L"Thread files\*(R" are used to store information about the news
  572. Xarticles and how they are all related to one another.
  573. X.PP
  574. X.I Mthreads
  575. Xneeds to be run
  576. Xperiodically \*(-- either in single-pass mode out of cron,
  577. Xor in daemon mode out of the boot script \*(-- to update the thread
  578. Xinformation whenever new news is received.
  579. XA site that gets its news feed during the night and doesn't need local
  580. Xpostings processed throughout the day can run
  581. X.I mthreads
  582. Xin single-pass mode once a day.
  583. XIf more processing is needed, either run
  584. X.I mthreads
  585. Xmore often or run it in daemon mode.
  586. XIn daemon mode, a background process is forked off that wakes up every 10
  587. Xminutes (by default) to check if the active file has been updated.
  588. X.SH INSTALLATION
  589. X.I Mthreads
  590. Xin installed in the RNLIB directory chosen during configuration.
  591. XWhen it is run for the first time, it will automatically create a file called
  592. X.I active2
  593. Xin the same directory.
  594. XThis file is essentially a copy of the active file that keeps the newsgroup
  595. Xtotals from the last run in one place.
  596. XIt is also used to choose which groups are to be processed into thread files.
  597. XAll groups start out as \*(L"unthreaded\*(R" unless they are turned on with
  598. Xa command like:
  599. X.IP
  600. Xmthreads all
  601. X.PP
  602. Xwhich would create thread file for all the groups.
  603. XFor testing purposes it is a good idea to start out small with a command
  604. Xlike:
  605. X.IP
  606. Xmthreads news
  607. X.PP
  608. Xwhich would thread only the news hierarchy.
  609. XThread processing can be turned on or off for individual groups or entire
  610. Xhierarchies by specifying the groups in a syntax very similar to that used
  611. Xin the sys file.
  612. XFor example, to turn on all of soc and talk except for talk.politics, and
  613. Xto turn off news.lists, use the following command once:
  614. X.IP
  615. Xmthreads soc,talk,!talk.politics,!news.lists
  616. X.PP
  617. XIf mthreads complains that another mthreads process is already running,
  618. Xit can be killed with the command:
  619. X.IP
  620. Xmthreads -k
  621. X.PP
  622. Xand then repeat the prior command after giving it a little time to die.
  623. X.PP
  624. XOnce all the desired groups are turned on, it is not necessary to
  625. Xspecify a hierarchy list for the normal functioning of mthreads.
  626. XIt can be used, however, to customize which new groups get turned on
  627. Xas they are created.
  628. X.SH LOGGING
  629. XAs mthreads executes, some status information (including error messages) 
  630. Xis placed in
  631. Xthe file mt.log in the RNLIB directory.
  632. XThis file will grow without bounds, and should be scanned periodically for
  633. Xerrors, and trimmed in size when it grows too large.
  634. XSee the shell script
  635. X.I mt.check
  636. Xfor an mt.log maintainer that will send mail if it finds database errors.
  637. X.SH OPTIONS
  638. X.TP 5
  639. X.B \-a
  640. Xis used to automatically turn on thread processing for new news groups as
  641. Xthey are created.
  642. XThe default is to leave new groups unthreaded.
  643. X.TP 5
  644. X.B \-D
  645. Xspecifies a debugging mode where only the groups mentioned on the
  646. Xcommand-line are processed \*(-- all other groups are left unchanged.
  647. XIt also outputs each group's name into the log file before it is processed.
  648. X.TP 5
  649. X.B \-d
  650. Xis used to specify the daemon mode, where
  651. X.I mthreads
  652. Xforks a background task that periodically wakes up and checks for an updated
  653. Xactive file.
  654. XThe number of minutes to wait after the completion of the last pass can
  655. Xbe specified after the '-d' option (e.g. -d20), otherwise it will default to
  656. X10 minutes.
  657. X.TP 5
  658. X.B \-e
  659. Xtells
  660. X.I mthreads
  661. Xto run an enhanced expiration check on the database.
  662. XWithout this option, only articles below the minimum field in the active
  663. Xfile are expired.
  664. XWith this option, all unexpired articles in the database are stat()'ed to
  665. Xsee if they actually exist.
  666. XIn single-pass mode the
  667. X.B -e
  668. Xoption always affects the current pass \*(-- use it
  669. Xonce a day after expire has run.
  670. XIn daemon mode, the
  671. X.B -e
  672. Xoption will cause one pass a day to be the enhanced expire pass.
  673. XBy default, this is the first time mthreads wakes up after 12:30 am.
  674. XIf a different time is desired, it can be specified in the form HHMM 
  675. X(e.g. -e2359).
  676. X.TP 5
  677. X.B -f
  678. Xis used to force
  679. X.I mthreads
  680. Xto open each and every thread file to see which ones really need to be
  681. Xupdated, not just the ones that differ in the active/active2 comparison.
  682. XIt will also remove any extraneous thread files from unthreaded groups
  683. X(which should only occur if you manually change the active2 file).
  684. XThis option should only be used when manipulating the thread files in
  685. Xunorthodox ways.
  686. X.TP 5
  687. X.B -k
  688. Xcan be used to terminate the currently running mthreads, just as if it
  689. Xhad received a terminate signal.
  690. XWhen this option is specified, no other activity is performed.
  691. X.TP 5
  692. X.B -n
  693. Xtells
  694. X.I mthreads
  695. Xthat no actual processing of thread files is to be performed.
  696. XThis can be used to just adjust which groups are to be processed, without
  697. Xactually doing any of the processing right away.
  698. X.TP 5
  699. X.B -s
  700. Xtells mthreads to sleep one second before processing each article.
  701. XThis is useful if your NNTP server cannot handle mthreads running at
  702. Xfull speed.
  703. XFor each additional
  704. X.B -s
  705. Xspecified, mthreads sleeps an additional second.
  706. X.TP 5
  707. X.B -v
  708. Xselects additional levels of verbosity in the log file.
  709. XThe default (without -v) is to log mthread's startup, the totals for each
  710. Xpass, the inclusion of the enhanced expire option, and major database errors.
  711. XAdd one
  712. X.B -v
  713. Xto get extra reference line problems logged into the file.
  714. XAdd a second and a third for even more (useless?) information.
  715. XA fourth will cause mthreads to output each group's name into the log file
  716. Xbefore it is processed.
  717. X.TP 5
  718. X.B -z
  719. Xtells mthreads to 'zap' any thread file it believes to be corrupt.
  720. XThis will allow the file to be regenerated from scratch on the next pass.
  721. X.TP 5
  722. X.B hierarchy_list
  723. XThe hierarchy list is used to turn thread processing on or off for the listed
  724. Xgroups.
  725. XThe groups are specified in a manner very similar to the news software's
  726. Xsys file:  \*(L"news\*(R" matches all groups in news; \*(L"!news\*(R" excludes
  727. Xall groups in news; \*(L"comp.all.ibm.pc,!comp.all.ibm.pc.all\*(L" matches both
  728. Xcomp.sys.ibm.pc and comp.binaries.ibm.pc, but not comp.binaries.ibm.pc.d.
  729. X.Sp
  730. XThe hierarchy_list is also used in conjunction with the debug flag to only
  731. Xprocess one or more groups for testing purposes.
  732. X.SH OUTPUT
  733. XWhen
  734. X.I mthreads
  735. Xis run in single-pass mode it generates a stream a status characters on
  736. Xstdout that present a visual display of what is happening.  If 
  737. Xsingle-pass mode is used for regular processing, this output can be
  738. Xredirected to /dev/null.
  739. X.Sp
  740. XThe output definitions:
  741. X.br
  742. X    \&'.' = group's entry is up-to-date
  743. X.br
  744. X    \&':' = group processed -- no change
  745. X.br
  746. X    \&'#' = group processed
  747. X.br
  748. X    \&'-' = group processed -- is now empty
  749. X.br
  750. X    \&'x' = group excluded in active
  751. X.br
  752. X    \&'X' = group excluded in active2
  753. X.br
  754. X    \&'*' = chdir failed (might be ok)
  755. X.br
  756. X    \&'!' = write failed (is NOT ok)
  757. X.br
  758. X    \&'e' = informational error
  759. X.br
  760. X    \&'E' = database-affecting error -- please report!
  761. X.SH CONFIGURATION
  762. XDuring the configuration of
  763. X.I trn
  764. Xa choice was made about where to place the thread data files.
  765. XThey either exist as a .thread file in each group's spool directory, or
  766. Xthey are a group.th file in a one-off directory structure on another drive.
  767. XSee the THREAD_DIR definition in config.h to review or change this definition.
  768. X.SH REBUILDING
  769. XIf the thread files are ever removed, also remove the file db.init in
  770. Xthe RNLIB directory.
  771. XThis file contains the byte-order of the machine that generated the database,
  772. Xand needs to be removed to truly start from scratch.
  773. XAn easy way to get
  774. X.I mthreads
  775. Xto remove all the files except for db.init is to specify the command:
  776. X.IP
  777. Xmthreads !all
  778. X.PP
  779. XThis also turns off thread processing for all groups.
  780. X.SH "ERROR HANDLING"
  781. XIf the active2 file is removed or corrupted, it will
  782. Xbe automatically rebuilt in the normal course of operation.
  783. XThe record of which groups should be threaded will be lost, however.
  784. XMissing/corrupted thread files are automatically re-built.
  785. X.SH EXAMPLES
  786. XRecommended commands to run on a regular basis are:
  787. X.IP
  788. Xmthreads -adve0630
  789. X.PP
  790. Xto start up an mthreads daemon in verbose logging mode that automatically
  791. Xthreads new groups and performs an extended expire at 6:30 am, or:
  792. X.IP
  793. Xmthreads -e >/dev/null
  794. X.PP
  795. Xto run an mthreads single-pass with extended expire that leaves new groups
  796. Xunthreaded.
  797. X.SH FILES
  798. X/usr/lib/news/active
  799. X.br
  800. X$RNLIB/active2
  801. X.br
  802. X$RNLIB/mt.log
  803. X.br
  804. X$RNLIB/db.init
  805. X.br
  806. X$RNLIB/LOCKmthreads
  807. X.br
  808. XLots of thread data files.
  809. X.SH AUTHOR
  810. XWayne Davison <davison@borland.com>
  811. END_OF_FILE
  812.   if test 9578 -ne `wc -c <'mthreads.1'`; then
  813.     echo shar: \"'mthreads.1'\" unpacked with wrong size!
  814.   fi
  815.   # end of 'mthreads.1'
  816. fi
  817. if test -f 'ngdata.c' -a "${1}" != "-c" ; then 
  818.   echo shar: Will not clobber existing file \"'ngdata.c'\"
  819. else
  820.   echo shar: Extracting \"'ngdata.c'\" \(8913 characters\)
  821.   sed "s/^X//" >'ngdata.c' <<'END_OF_FILE'
  822. X/* $Header: ngdata.c,v 4.3.3.2 91/01/16 03:18:21 davison Trn $
  823. X *
  824. X * $Log:    ngdata.c,v $
  825. X * Revision 4.3.3.2  91/01/16  03:18:21  davison
  826. X * Integrated rn patches 48-54.  Fixed bug in ZEROGLOB code.
  827. X * 
  828. X * Revision 4.3.3.1  90/07/21  20:28:27  davison
  829. X * Initial Trn Release
  830. X * 
  831. X * Revision 4.3.2.11  90/11/22  16:14:34  sob
  832. X * Added changes to accomodate picky C preprocessors
  833. X * 
  834. X * Revision 4.3.2.10  90/04/14  22:05:15  sob
  835. X * Removed redundant declaration of active_name
  836. X * 
  837. X * Revision 4.3.2.9  90/03/22  23:04:55  sob
  838. X * Fixes provided by Wayne Davison <drivax!davison>
  839. X * 
  840. X * Revision 4.3.2.8  90/03/17  20:50:51  sob
  841. X * Fixes provided by stewart@netxcom.iad-nxe.global-mis.dhl.com to handle
  842. X * flaky transfers of the active file from the server.
  843. X * 
  844. X * Revision 4.3.2.7  90/03/17  17:11:08  sob
  845. X * Added support for CNEWS active file flags.
  846. X *
  847. X * Revision 4.3.2.6  89/12/08  22:42:04  sob
  848. X * Corrected typo in an #ifdef statement pointed out by
  849. X * jik@pit-manager.mit.edu
  850. X * 
  851. X * Revision 4.3.2.5  89/11/28  01:51:14  sob
  852. X * Removed redundant #include directive.
  853. X * 
  854. X * Revision 4.3.2.4  89/11/27  01:31:07  sob
  855. X * Altered NNTP code per ideas suggested by Bela Lubkin
  856. X * <filbo@gorn.santa-cruz.ca.us>
  857. X * 
  858. X * Revision 4.3.2.3  89/11/08  02:41:40  sob
  859. X * Removed unneeded subroutine.
  860. X * 
  861. X * Revision 4.3.2.2  89/11/08  02:24:31  sob
  862. X * Integrated modifications from other RRN patches colleceted from USENET
  863. X * 
  864. X * Revision 4.3.2.1  89/11/06  00:42:43  sob
  865. X * Added RRN support from NNTP 1.5
  866. X * 
  867. X * Revision 4.3  85/05/01  11:44:38  lwall
  868. X * Baseline for release with 4.3bsd.
  869. X * 
  870. X */
  871. X
  872. X#include "EXTERN.h"
  873. X#include "common.h"
  874. X#include "ndir.h"
  875. X#include "rcstuff.h"
  876. X#include "rn.h"
  877. X#include "intrp.h"
  878. X#include "final.h"
  879. X#include "rcln.h"
  880. X#include "util.h"
  881. X#ifdef SERVER
  882. X#include "server.h"
  883. X#endif
  884. X#include "INTERN.h"
  885. X#include "ngdata.h"
  886. X
  887. Xvoid
  888. Xngdata_init()
  889. X{
  890. X#ifdef SERVER
  891. X    char ser_line[256];
  892. X    int entries;
  893. X#endif
  894. X    char *cp;
  895. X
  896. X/* The following is only for systems that do not zero globals properly */
  897. X#ifdef ZEROGLOB
  898. X# ifdef CACHEFIRST
  899. X  {
  900. X    int i;
  901. X    for (i=0; i<MAXRCLINE; i++)
  902. X    abs1st[i] = 0;
  903. X  }
  904. X# endif
  905. X#endif    /* ZEROGLOB */
  906. X
  907. X    /* open the active file */
  908. X
  909. X#ifdef SERVER
  910. X
  911. X#ifdef USETHREADS
  912. X    if (use_threads) {
  913. X    cp = filexp(ACTIVE2);
  914. X    actfp = fopen(cp,"r");
  915. X    if (actfp == Nullfp) {
  916. X        printf(cantopen,cp) FLUSH;
  917. X        finalize(1);
  918. X    }
  919. X    return;
  920. X    }
  921. X#endif
  922. X
  923. X    put_server("LIST");        /* tell server we want the active file */
  924. X    get_server(ser_line, sizeof(ser_line));
  925. X    if (*ser_line != CHAR_OK) {        /* and then see if that's ok */
  926. X    fprintf(stdout, "Can't get active file from server: \n%s\n", ser_line);
  927. X    finalize(1);
  928. X    }
  929. X
  930. X    cp = filexp("/tmp/rrnact.%$");    /* make a temporary name */
  931. X    strcpy(active_name, cp);
  932. X    actfp = fopen(active_name, "w+");    /* and get ready */
  933. X    if (actfp == Nullfp) {
  934. X    printf(cantopen,active_name) FLUSH;
  935. X    finalize(1);
  936. X    }
  937. X
  938. X    entries = 0;
  939. X    while (1) {
  940. X    if (get_server(ser_line, sizeof(ser_line)) < 0) {
  941. X        printf("Can't get active file from server:\ntransfer failed after %d entries\n", entries);
  942. X        finalize(1);
  943. X    }
  944. X    if (ser_line[0] == '.')        /* while there's another line */
  945. X        break;            /* get it and write it to */
  946. X    entries++;
  947. X    fputs(ser_line, actfp);
  948. X    putc('\n', actfp);
  949. X    }
  950. X
  951. X    fseek(actfp,0L,0);        /* just get to the beginning */
  952. X
  953. X#else /* not SERVER */
  954. X
  955. X#ifdef USETHREADS
  956. X    if (use_threads)
  957. X    cp = filexp(ACTIVE2);
  958. X    else
  959. X#endif
  960. X    cp = filexp(ACTIVE);
  961. X    actfp = fopen(cp,"r");
  962. X    if (actfp == Nullfp) {
  963. X    printf(cantopen,cp) FLUSH;
  964. X    finalize(1);
  965. X    }
  966. X#endif
  967. X}
  968. X
  969. X/* find the maximum article number of a newsgroup */
  970. X
  971. XART_NUM
  972. Xgetngsize(num)
  973. Xregister NG_NUM num;
  974. X{
  975. X    register int len;
  976. X    register char *nam;
  977. X    char tmpbuf[80];
  978. X    ART_POS oldsoft;
  979. X
  980. X    nam = rcline[num];
  981. X    len = rcnums[num] - 1;
  982. X    softtries++;
  983. X#ifdef DEBUGGING
  984. X    if (debug & DEB_SOFT_POINTERS)
  985. X    printf("Softptr = %ld\n",(long)softptr[num]) FLUSH;
  986. X#endif
  987. X    oldsoft = softptr[num];
  988. X    if ((softptr[num] = findact(tmpbuf, nam, len, (long)oldsoft)) >= 0) {
  989. X    if (softptr[num] != oldsoft) {
  990. X        softmisses++;
  991. X        writesoft = TRUE;
  992. X    }
  993. X    }
  994. X    else {
  995. X    softptr[num] = 0;
  996. X    if (rcchar[num] == ':')        /* unsubscribe quietly */
  997. X        rcchar[num] = NEGCHAR;
  998. X    return TR_BOGUS;        /* well, not so quietly, actually */
  999. X    }
  1000. X    
  1001. X#ifdef DEBUGGING
  1002. X    if (debug & DEB_SOFT_POINTERS) {
  1003. X    printf("Should be %ld\n",(long)softptr[num]) FLUSH;
  1004. X    }
  1005. X#endif
  1006. X#ifdef MININACT
  1007. X    {
  1008. X    register char *s, ch;
  1009. X    ART_NUM tmp;
  1010. X
  1011. X    for (s=tmpbuf+len+1; isdigit(*s); s++) ;
  1012. X    if (tmp = atol(s))
  1013. X#ifdef CACHEFIRST
  1014. X        abs1st[num] = tmp;
  1015. X#else
  1016. X        abs1st = tmp;
  1017. X#endif
  1018. X    if (!in_ng) {
  1019. X        for (s++; isdigit(*s); s++) ;
  1020. X        while (isspace(*s)) s++;
  1021. X        ch = *s;
  1022. X#ifdef USETHREADS
  1023. X        if (isupper(ch)) {
  1024. X        ch = tolower(ch);
  1025. X        ThreadedGroup = FALSE;
  1026. X        } else
  1027. X        ThreadedGroup = use_threads;
  1028. X#endif
  1029. X        switch (ch) {
  1030. X        case 'n': moderated = getval("NOPOSTRING"," (no posting)"); break;
  1031. X        case 'm': moderated = getval("MODSTRING", " (moderated)"); break;
  1032. X        /* This shouldn't even occur.  What are we doing in a non-existent
  1033. X           group?  Disallow it. */
  1034. X        case 'x': return TR_BOGUS;
  1035. X        /* what should be done about refiled groups?  rn shouldn't even
  1036. X           be in them (ie, if sci.aquaria is refiled to rec.aquaria, then
  1037. X           get the news there) */
  1038. X        case '=': return TR_BOGUS;
  1039. X        default: moderated = nullstr;
  1040. X        }
  1041. X    }
  1042. X    }
  1043. X#endif
  1044. X    return atol(tmpbuf+len+1);
  1045. X}
  1046. X
  1047. XACT_POS
  1048. Xfindact(outbuf,nam,len,suggestion)
  1049. Xchar *outbuf;
  1050. Xchar *nam;
  1051. Xint len;
  1052. Xlong suggestion;
  1053. X{
  1054. X    ACT_POS retval;
  1055. X
  1056. X    fseek(actfp,100000L,1);    /* hopefully this forces a reread */
  1057. X    if (suggestion == 0L || fseek(actfp,suggestion,0) < 0 ||
  1058. X      fgets(outbuf,80,actfp) == Nullch ||
  1059. X      outbuf[len] != ' ' ||
  1060. X      strnNE(outbuf,nam,len)) {
  1061. X#ifdef DEBUGGING
  1062. X    if (debug & DEB_SOFT_POINTERS)
  1063. X        printf("Missed, looking for %s in %sLen = %d\n",nam,outbuf,len)
  1064. X          FLUSH;
  1065. X#endif
  1066. X    fseek(actfp,0L,0);
  1067. X#ifndef lint
  1068. X    retval = (ACT_POS)ftell(actfp);
  1069. X#else
  1070. X    retval = Null(ACT_POS);
  1071. X#endif /* lint */
  1072. X    while (fgets(outbuf,80,actfp) != Nullch) {
  1073. X        if (outbuf[len] == ' ' && strnEQ(outbuf,nam,len))
  1074. X        return retval;
  1075. X#ifndef lint
  1076. X        retval = (ACT_POS) ftell(actfp);
  1077. X#endif /* lint */
  1078. X    }
  1079. X    return (ACT_POS) -1;        /* well, not so quietly, actually */
  1080. X    }
  1081. X    else
  1082. X#ifndef lint
  1083. X    return (ACT_POS) suggestion;
  1084. X#else
  1085. X    return retval;
  1086. X#endif /* lint */
  1087. X    /*NOTREACHED*/
  1088. X}
  1089. X
  1090. X/* determine the absolutely first existing article number */
  1091. X#ifdef SERVER
  1092. XART_NUM
  1093. Xgetabsfirst(ngnum,ngsize)
  1094. Xregister NG_NUM ngnum;
  1095. XART_NUM ngsize;
  1096. X{
  1097. X    register ART_NUM a1st;
  1098. X#ifndef MININACT
  1099. X    char ser_line[256];
  1100. X    ART_NUM x,y;
  1101. X#endif
  1102. X
  1103. X#ifdef CACHEFIRST
  1104. X    if (a1st = abs1st[ngnum])
  1105. X    return a1st;
  1106. X#endif
  1107. X#ifdef MININACT
  1108. X    getngsize(ngnum);
  1109. X# ifdef CACHEFIRST
  1110. X    return abs1st[ngnum];
  1111. X# else
  1112. X    return abs1st;
  1113. X# endif
  1114. X#else
  1115. X    sprintf(cp,"GROUP %s",rcline[ngnum]);
  1116. X    put_server(cp);
  1117. X    if (get_server(ser_line, sizeof(ser_line)) < 0) {
  1118. X    fprintf(stderr, "rrn: Unexpected close of server socket.\n");
  1119. X    finalize(1);
  1120. X    }
  1121. X    if (*ser_line != CHAR_OK) {        /* and then see if that's ok */
  1122. X    a1st = ngsize+1;        /* nothing there */
  1123. X    }
  1124. X    (void) sscanf(ser_line,"%d%d%d",&x,&y,&a1st);
  1125. X# ifdef CACHEFIRST
  1126. X    abs1st[ngnum] = a1st;
  1127. X# endif
  1128. X    return a1st;
  1129. X#endif
  1130. X}
  1131. X/* we already know the lowest article number with NNTP */
  1132. XART_NUM
  1133. Xgetngmin(dirname,floor)
  1134. Xchar *dirname;
  1135. XART_NUM floor;
  1136. X{
  1137. X    return(floor);
  1138. X}
  1139. X#else
  1140. XART_NUM
  1141. Xgetabsfirst(ngnum,ngsize)
  1142. Xregister NG_NUM ngnum;
  1143. XART_NUM ngsize;
  1144. X{
  1145. X    register ART_NUM a1st;
  1146. X#ifndef MININACT
  1147. X    char dirname[MAXFILENAME];
  1148. X#endif
  1149. X
  1150. X#ifdef CACHEFIRST
  1151. X    if (a1st = abs1st[ngnum])
  1152. X    return a1st;
  1153. X#endif
  1154. X#ifdef MININACT
  1155. X    getngsize(ngnum);
  1156. X# ifdef CACHEFIRST
  1157. X    return abs1st[ngnum];
  1158. X# else
  1159. X    return abs1st;
  1160. X# endif
  1161. X#else /* not MININACT */
  1162. X    sprintf(dirname,"%s/%s",spool,getngdir(rcline[ngnum]));
  1163. X    a1st = getngmin(dirname,0L);
  1164. X    if (!a1st)                /* nothing there at all? */
  1165. X    a1st = ngsize+1;        /* aim them at end of newsgroup */
  1166. X# ifdef CACHEFIRST
  1167. X    abs1st[ngnum] = a1st;
  1168. X# endif
  1169. X    return a1st;
  1170. X#endif /* MININACT */
  1171. X}
  1172. X
  1173. X/* scan a directory for minimum article number greater than floor */
  1174. X
  1175. XART_NUM
  1176. Xgetngmin(dirname,floor)
  1177. Xchar *dirname;
  1178. XART_NUM floor;
  1179. X{
  1180. X    register DIR *dirp;
  1181. X    register struct DIRTYPE *dp;
  1182. X    register ART_NUM min = 1000000;
  1183. X    register ART_NUM maybe;
  1184. X    register char *p;
  1185. X    char tmpbuf[128];
  1186. X    
  1187. X    dirp = opendir(dirname);
  1188. X    if (!dirp)
  1189. X    return 0;
  1190. X    while ((dp = readdir(dirp)) != Null(struct DIRTYPE *)) {
  1191. X    if ((maybe = atol(dp->d_name)) < min && maybe > floor) {
  1192. X        for (p = dp->d_name; *p; p++)
  1193. X        if (!isdigit(*p))
  1194. X            goto nope;
  1195. X        if (*dirname == '.' && !dirname[1])
  1196. X        stat(dp->d_name, &filestat);
  1197. X        else {
  1198. X        sprintf(tmpbuf,"%s/%s",dirname,dp->d_name);
  1199. X        stat(tmpbuf, &filestat);
  1200. X        }
  1201. X        if (! (filestat.st_mode & S_IFDIR))
  1202. X        min = maybe;
  1203. X    }
  1204. X      nope:
  1205. X    ;
  1206. X    }
  1207. X    closedir(dirp);
  1208. X    return min==1000000 ? 0 : min;
  1209. X}
  1210. X#endif
  1211. END_OF_FILE
  1212.   if test 8913 -ne `wc -c <'ngdata.c'`; then
  1213.     echo shar: \"'ngdata.c'\" unpacked with wrong size!
  1214.   fi
  1215.   # end of 'ngdata.c'
  1216. fi
  1217. if test -f 'ngstuff.c' -a "${1}" != "-c" ; then 
  1218.   echo shar: Will not clobber existing file \"'ngstuff.c'\"
  1219. else
  1220.   echo shar: Extracting \"'ngstuff.c'\" \(10924 characters\)
  1221.   sed "s/^X//" >'ngstuff.c' <<'END_OF_FILE'
  1222. X/* $Header: ngstuff.c,v 4.3.3.3 91/01/16 03:18:25 davison Trn $
  1223. X *
  1224. X * $Log:    ngstuff.c,v $
  1225. X * Revision 4.3.3.3  91/01/16  03:18:25  davison
  1226. X * Changed some expressions to registers to bypass a compiler problem.
  1227. X * 
  1228. X * Revision 4.3.3.2  90/08/20  18:29:08  davison
  1229. X * Expanded path arrays for consistancy.
  1230. X * 
  1231. X * Revision 4.3.3.1  90/07/21  20:29:12  davison
  1232. X * Initial Trn Release
  1233. X * 
  1234. X * Revision 4.3.2.2  90/04/14  19:40:02  sob
  1235. X * Fixed small syntax problem that generates errors with particular C
  1236. X * preprocessors.
  1237. X *
  1238. X * Revision 4.3.1.2  85/05/10  14:31:52  lwall
  1239. X * Prevented "Junked" or "Marked unread" when no state change.
  1240. X * 
  1241. X * Revision 4.3.1.1  85/05/10  11:36:45  lwall
  1242. X * Branch for patches.
  1243. X * 
  1244. X * Revision 4.3  85/05/01  11:45:03  lwall
  1245. X * Baseline for release with 4.3bsd.
  1246. X * 
  1247. X */
  1248. X
  1249. X#include "EXTERN.h"
  1250. X#include "common.h"
  1251. X#include "term.h"
  1252. X#include "util.h"
  1253. X#include "ng.h"
  1254. X#include "bits.h"
  1255. X#include "intrp.h"
  1256. X#include "cheat.h"
  1257. X#include "head.h"
  1258. X#include "final.h"
  1259. X#include "sw.h"
  1260. X#ifdef USETHREADS
  1261. X#include "rthreads.h"
  1262. X#include "rn.h"
  1263. X#include "rcstuff.h"
  1264. X#endif
  1265. X#include "uudecode.h"
  1266. X#include "INTERN.h"
  1267. X#include "ngstuff.h"
  1268. X
  1269. Xvoid
  1270. Xngstuff_init()
  1271. X{
  1272. X    ;
  1273. X}
  1274. X
  1275. X/* do a shell escape */
  1276. X
  1277. Xint
  1278. Xescapade()
  1279. X{
  1280. X    register char *s;
  1281. X    bool interactive = (buf[1] == FINISHCMD);
  1282. X    bool docd;
  1283. X    char whereiam[512];
  1284. X
  1285. X    if (!finish_command(interactive))    /* get remainder of command */
  1286. X    return -1;
  1287. X    s = buf+1;
  1288. X    docd = *s != '!';
  1289. X    if (!docd) {
  1290. X    s++;
  1291. X    }
  1292. X    else {
  1293. X    getwd(whereiam);
  1294. X    if (chdir(cwd)) {
  1295. X        printf(nocd,cwd) FLUSH;
  1296. X        sig_catcher(0);
  1297. X    }
  1298. X    }
  1299. X    while (*s == ' ') s++;
  1300. X                    /* skip leading spaces */
  1301. X    interp(cmd_buf, (sizeof cmd_buf), s);/* interpret any % escapes */
  1302. X    resetty();                /* make sure tty is friendly */
  1303. X    doshell(Nullch,cmd_buf);    /* invoke the shell */
  1304. X    noecho();                /* and make terminal */
  1305. X    crmode();                /*   unfriendly again */
  1306. X    if (docd) {
  1307. X    if (chdir(whereiam)) {
  1308. X        printf(nocd,whereiam) FLUSH;
  1309. X        sig_catcher(0);
  1310. X    }
  1311. X    }
  1312. X#ifdef MAILCALL
  1313. X    mailcount = 0;            /* force recheck */
  1314. X#endif
  1315. X    return 0;
  1316. X}
  1317. X
  1318. X/* process & command */
  1319. X
  1320. Xint
  1321. Xswitcheroo()
  1322. X{
  1323. X    if (!finish_command(TRUE)) /* get rest of command */
  1324. X    return -1;    /* if rubbed out, try something else */
  1325. X    if (!buf[1])
  1326. X    pr_switches();
  1327. X#ifdef PUSHBACK
  1328. X    else if (buf[1] == '&') {
  1329. X    if (!buf[2]) {
  1330. X        page_init();
  1331. X        show_macros();
  1332. X    }
  1333. X    else {
  1334. X        char tmpbuf[LBUFLEN];
  1335. X        register char *s;
  1336. X
  1337. X        for (s=buf+2; isspace(*s); s++);
  1338. X        mac_line(s,tmpbuf,(sizeof tmpbuf));
  1339. X    }
  1340. X    }
  1341. X#endif
  1342. X    else {
  1343. X    bool docd = (instr(buf,"-d") != Nullch);
  1344. X     char whereami[512];
  1345. X    if (docd)
  1346. X        getwd(whereami);
  1347. X    sw_list(buf+1);
  1348. X    if (docd) {
  1349. X        cwd_check();
  1350. X        if (chdir(whereami)) {        /* -d does chdirs */
  1351. X        printf(nocd,whereami) FLUSH;
  1352. X        sig_catcher(0);
  1353. X        }
  1354. X    }
  1355. X    }
  1356. X    return 0;
  1357. X}
  1358. X
  1359. X/* process range commands */
  1360. X
  1361. Xint
  1362. Xnumnum()
  1363. X{
  1364. X    ART_NUM min, max;
  1365. X    char *cmdlst = Nullch;
  1366. X    register char *s, *c;
  1367. X    ART_NUM oldart = art;
  1368. X    char tmpbuf[LBUFLEN];
  1369. X    bool justone = TRUE;        /* assume only one article */
  1370. X
  1371. X    perform_cnt = 0;
  1372. X    if (!finish_command(TRUE))    /* get rest of command */
  1373. X    return NN_INP;
  1374. X    if (lastart < 1) {
  1375. X        fputs("\nNo articles\n",stdout) FLUSH;
  1376. X        return NN_ASK;
  1377. X    }
  1378. X#ifdef ARTSRCH
  1379. X    if (srchahead)
  1380. X    srchahead = -1;
  1381. X#endif
  1382. X    for (s=buf; *s && (isdigit(*s) || index(" ,-.$",*s)); s++)
  1383. X    if (!isdigit(*s))
  1384. X        justone = FALSE;
  1385. X    if (*s) {
  1386. X    cmdlst = savestr(s);
  1387. X    justone = FALSE;
  1388. X    }
  1389. X    else if (!justone)
  1390. X    cmdlst = savestr("m");
  1391. X    *s++ = ',';
  1392. X    *s = '\0';
  1393. X    safecpy(tmpbuf,buf,LBUFLEN);
  1394. X    for (s = tmpbuf; c = index(s,','); s = ++c) {
  1395. X    *c = '\0';
  1396. X    if (*s == '.')
  1397. X        min = oldart;
  1398. X    else
  1399. X        min = atol(s);
  1400. X#ifdef USETHREADS
  1401. X    if (min<absfirst && justone) {
  1402. X        int r;
  1403. X
  1404. X        /* Check if this is a root number */
  1405. X        for (r = 0; r < total.root; r++) {
  1406. X        if (p_roots[r].root_num == min) {
  1407. X            p_art = p_articles + p_roots[r].articles;
  1408. X            art = p_art->num;
  1409. X            if (p_art->subject == -1) {
  1410. X            follow_thread('N');
  1411. X            }
  1412. X            return NN_REREAD;
  1413. X        }
  1414. X        }
  1415. X    }
  1416. X#endif
  1417. X    if (min<absfirst) {        /* make sure it is reasonable */
  1418. X        min = absfirst;
  1419. X        printf("(First article is %ld)\n",(long)absfirst) FLUSH;
  1420. X        pad(just_a_sec/3);
  1421. X    }
  1422. X    if ((s=index(s,'-')) != Nullch) {
  1423. X        s++;
  1424. X        if (*s == '$')
  1425. X        max = lastart;
  1426. X        else if (*s == '.')
  1427. X        max = oldart;
  1428. X        else
  1429. X        max = atol(s);
  1430. X    }
  1431. X    else
  1432. X        max = min;
  1433. X    if (max>lastart) {
  1434. X        max = lastart;
  1435. X        if (min > max)
  1436. X        min = max;
  1437. X        printf("(Last article is %ld)\n",(long)lastart) FLUSH;
  1438. X        pad(just_a_sec/3);
  1439. X    }
  1440. X    if (max < min) {
  1441. X        fputs("\nBad range\n",stdout) FLUSH;
  1442. X        if (cmdlst)
  1443. X        free(cmdlst);
  1444. X        return NN_ASK;
  1445. X    }
  1446. X    if (justone) {
  1447. X        art = min;
  1448. X        return NN_REREAD;
  1449. X    }
  1450. X    check_first(min);
  1451. X    for (art=min; art<=max; art++) {
  1452. X        if (perform(cmdlst,TRUE)) {
  1453. X#ifdef VERBOSE
  1454. X        IF(verbose)
  1455. X            printf("\n(Interrupted at article %ld)\n",(long)art)
  1456. X              FLUSH;
  1457. X        ELSE
  1458. X#endif
  1459. X#ifdef TERSE
  1460. X            printf("\n(Intr at %ld)\n",(long)art) FLUSH;
  1461. X#endif
  1462. X        if (cmdlst)
  1463. X            free(cmdlst);
  1464. X        return NN_ASK;
  1465. X        }
  1466. X    }
  1467. X    }
  1468. X    art = oldart;
  1469. X    if (cmdlst)
  1470. X    free(cmdlst);
  1471. X    return NN_NORM;
  1472. X}
  1473. X
  1474. X#ifdef USETHREADS
  1475. Xint
  1476. Xuse_selected()
  1477. X{
  1478. X    PACKED_ARTICLE *root_limit;
  1479. X    register char *s, ch;
  1480. X    register int r;
  1481. X    char *cmdstr;
  1482. X    int ret = 1, orig_root_cnt = selected_root_cnt;
  1483. X
  1484. X    if (!finish_command(TRUE))    /* get rest of command */
  1485. X    return 0;
  1486. X    if (!(ch = buf[1]))
  1487. X    return -1;
  1488. X    cmdstr = savestr(buf+1);
  1489. X
  1490. X    perform_cnt = 0;
  1491. X    page_line = 1;
  1492. X
  1493. X    /* Multiple commands and commands that operate on individual articles
  1494. X    ** use the article loop.
  1495. X    */
  1496. X    if (strlen(cmdstr) > 1 || index("ejmMsSwW|=", ch)) {
  1497. X    bool want_unread = (unread_selector || ch == 'm');
  1498. X
  1499. X    for (r = 0; r < total.root; r++) {
  1500. X        if (scan_all_roots
  1501. X         || (!orig_root_cnt&&root_article_cnts[r]&&!(selected_roots[r]&4))
  1502. X         || (selected_roots[r] & (unread_selector+1))) {
  1503. X        p_art = p_articles + p_roots[r].articles;
  1504. X        root_limit = upper_limit( p_art, 0 );
  1505. X        for (; p_art < root_limit; p_art++) {
  1506. X            art = p_art->num;
  1507. X            if (p_art->subject != -1
  1508. X             && (!was_read(art) ^ want_unread)) {
  1509. X            if (perform(cmdstr, TRUE)) {
  1510. X                fputs("\nInterrupted\n", stdout) FLUSH;
  1511. X                goto break_out;
  1512. X            }
  1513. X            }
  1514. X            if (p_art == Nullart)
  1515. X            break;
  1516. X        }/* for all articles */
  1517. X        }/* if selected */
  1518. X    }/* for all threads */
  1519. X    }                /* other commands get the root loop */
  1520. X    else if (ch == '+' || ch == '-' || ch == 'J' || ch == 'T' || ch == 't') {
  1521. X    for (r = 0; r < total.root; r++) {
  1522. X        if (scan_all_roots
  1523. X         || (!orig_root_cnt&&root_article_cnts[r]&&!(selected_roots[r]&4))
  1524. X         || (selected_roots[r] & (unread_selector+1))) {
  1525. X        if (mode != 't' && ch != 't') {
  1526. X            printf("T%-5ld ", (long)p_roots[r].root_num);
  1527. X        }
  1528. X        p_art = p_articles + p_roots[r].articles;
  1529. X        art = p_art->num;
  1530. X        if (perform(cmdstr, FALSE)) {
  1531. X            fputs("\nInterrupted\n", stdout) FLUSH;
  1532. X            goto break_out;
  1533. X        }
  1534. X#ifdef VERBOSE
  1535. X        IF(verbose)
  1536. X            if (mode != 't' && ch != 't' && ch != 'T')
  1537. X            putchar('\n') FLUSH;
  1538. X#endif
  1539. X        }
  1540. X    }
  1541. X    }
  1542. X    else if (ch == 'E') {    /* one command needs no looping at all */
  1543. X    if (uu_out != Nullfp) {
  1544. X        uud_end();
  1545. X    } else {
  1546. X        ret = 2;
  1547. X    }
  1548. X    }
  1549. X    else {
  1550. X    printf("???%s\n",cmdstr);
  1551. X    ret = -1;
  1552. X    }
  1553. X  break_out:
  1554. X    free(cmdstr);
  1555. X    return ret;
  1556. X}
  1557. X#endif
  1558. X
  1559. Xint
  1560. Xperform(cmdlst,toplevel)
  1561. Xregister char *cmdlst;
  1562. Xint toplevel;
  1563. X{
  1564. X    register int ch;
  1565. X    
  1566. X    if (toplevel) {
  1567. X    printf("%-6ld ",art);
  1568. X    fflush(stdout);
  1569. X    }
  1570. X    perform_cnt++;
  1571. X    for (; ch = *cmdlst; cmdlst++) {
  1572. X    if (isspace(ch) || ch == ':')
  1573. X        continue;
  1574. X    if (ch == 'j') {
  1575. X        if (!was_read(art)) {
  1576. X        mark_as_read();
  1577. X#ifdef VERBOSE
  1578. X        IF(verbose)
  1579. X            fputs("\tJunked",stdout);
  1580. X#endif
  1581. X        }
  1582. X    }
  1583. X#ifdef USETHREADS
  1584. X    else if (ch == '+') {
  1585. X      register char mask = unread_selector+1;
  1586. X        find_article(art);
  1587. X        if (p_art && !(selected_roots[p_art->root] & mask)) {
  1588. X          register int r = p_art->root;
  1589. X        selected_roots[r] |= mask;
  1590. X        selected_root_cnt++;
  1591. X        if (mode == 't') {
  1592. X            selected_count += root_article_cnts[r];
  1593. X        } else {
  1594. X            selected_count += count_one_root(r);
  1595. X#ifdef VERBOSE
  1596. X            IF(verbose)
  1597. X            fputs("\tSelected",stdout);
  1598. X#endif
  1599. X        }
  1600. X        }
  1601. X    }
  1602. X    else if (ch == '-') {
  1603. X      register char mask = unread_selector+1;
  1604. X        find_article(art);
  1605. X        if (p_art && selected_root_cnt
  1606. X         && (selected_roots[p_art->root] & mask)) {
  1607. X          register int r = p_art->root;
  1608. X        selected_roots[r] &= ~mask;
  1609. X        selected_root_cnt--;
  1610. X        if (mode == 't') {
  1611. X            selected_count -= root_article_cnts[r];
  1612. X        } else {
  1613. X            selected_count -= count_one_root(r);
  1614. X#ifdef VERBOSE
  1615. X            IF(verbose)
  1616. X            fputs("\tDeselected",stdout);
  1617. X#endif
  1618. X        }
  1619. X        }
  1620. X    }
  1621. X    else if (ch == 't') {
  1622. X        find_article(art);
  1623. X        entire_tree();
  1624. X    }
  1625. X    else if (ch == 'J' || ch == 'T') {
  1626. X        char tmpbuf[128];
  1627. X        ART_NUM oldart = art;
  1628. X
  1629. X        find_article(art);
  1630. X        if (p_art) {
  1631. X        if (ch == 'T') {
  1632. X            sprintf(tmpbuf,"T%ld\t# %s",
  1633. X            (long)p_roots[p_art->root].root_num,
  1634. X            subject_ptrs[p_art->subject]);
  1635. X            fputs(tmpbuf,stdout);
  1636. X            kf_append(tmpbuf);
  1637. X        }
  1638. X        follow_thread('J');
  1639. X        art = oldart;
  1640. X        }
  1641. X    }
  1642. X#endif
  1643. X    else if (ch == 'm') {
  1644. X        if (was_read(art)) {
  1645. X        unmark_as_read();
  1646. X#ifdef VERBOSE
  1647. X        IF(verbose)
  1648. X            fputs("\tMarked unread",stdout);
  1649. X#endif
  1650. X        }
  1651. X    }
  1652. X    else if (ch == 'M') {
  1653. X#ifdef DELAYMARK
  1654. X        delay_unmark(art);
  1655. X#ifdef VERBOSE
  1656. X        IF(verbose)
  1657. X        fputs("\tWill return",stdout);
  1658. X#endif
  1659. X#else
  1660. X        notincl("M");
  1661. X        return -1;
  1662. X#endif
  1663. X    }
  1664. X    else if (ch == '=') {
  1665. X        printf("\t%s",fetchsubj(art,FALSE,FALSE));
  1666. X#ifdef VERBOSE
  1667. X        IF(verbose)
  1668. X        ;
  1669. X        ELSE
  1670. X#endif
  1671. X        putchar('\n') FLUSH;        /* ghad! */
  1672. X    }
  1673. X    else if (ch == 'C') {
  1674. X#ifdef ASYNC_PARSE
  1675. X        printf("\t%sancelled",(cancel_article() ? "Not c" : "C"));
  1676. X#else
  1677. X        notincl("C");
  1678. X        return -1;
  1679. X#endif
  1680. X    }
  1681. X    else if (ch == '%') {
  1682. X#ifdef ASYNC_PARSE
  1683. X        char tmpbuf[512];
  1684. X
  1685. X        if (one_command)
  1686. X        interp(tmpbuf, (sizeof tmpbuf), cmdlst);
  1687. X        else
  1688. X        cmdlst = dointerp(tmpbuf, (sizeof tmpbuf), cmdlst, ":") - 1;
  1689. X        perform_cnt--;
  1690. X        if (perform(tmpbuf,FALSE))
  1691. X        return -1;
  1692. X#else
  1693. X        notincl("%");
  1694. X        return -1;
  1695. X#endif
  1696. X    }
  1697. X    else if (index("!&sSwWe|",ch)) {
  1698. X        if (one_command)
  1699. X        strcpy(buf,cmdlst);
  1700. X        else
  1701. X        cmdlst = cpytill(buf,cmdlst,':') - 1;
  1702. X        /* we now have the command in buf */
  1703. X        if (ch == '!') {
  1704. X        escapade();
  1705. X#ifdef VERBOSE
  1706. X        IF(verbose)
  1707. X            fputs("\tShell escaped",stdout);
  1708. X#endif
  1709. X        }
  1710. X        else if (ch == '&') {
  1711. X        switcheroo();
  1712. X#ifdef VERBOSE
  1713. X        IF(verbose)
  1714. X            if (buf[1] && buf[1] != '&')
  1715. X            fputs("\tSwitched",stdout);
  1716. X#endif
  1717. X        }
  1718. X        else {
  1719. X        putchar('\t');
  1720. X        save_article();
  1721. X#ifdef VERBOSE
  1722. X        IF(verbose)
  1723. X            ;
  1724. X        ELSE
  1725. X#endif
  1726. X            putchar('\n') FLUSH;
  1727. X        }
  1728. X    }
  1729. X    else {
  1730. X        printf("\t???%s\n",cmdlst);
  1731. X        return -1;
  1732. X    }
  1733. X#ifdef VERBOSE
  1734. X    fflush(stdout);
  1735. X#endif
  1736. X    if (one_command)
  1737. X        break;
  1738. X    }
  1739. X    if (toplevel) {
  1740. X#ifdef VERBOSE
  1741. X    IF(verbose)
  1742. X        putchar('\n') FLUSH;
  1743. X#endif
  1744. X    }
  1745. X    if( int_count ) {
  1746. X    int_count = 0;
  1747. X    return -1;
  1748. X    }
  1749. X    return 0;
  1750. X}
  1751. END_OF_FILE
  1752.   if test 10924 -ne `wc -c <'ngstuff.c'`; then
  1753.     echo shar: \"'ngstuff.c'\" unpacked with wrong size!
  1754.   fi
  1755.   # end of 'ngstuff.c'
  1756. fi
  1757. if test -f 'term.h' -a "${1}" != "-c" ; then 
  1758.   echo shar: Will not clobber existing file \"'term.h'\"
  1759. else
  1760.   echo shar: Extracting \"'term.h'\" \(8474 characters\)
  1761.   sed "s/^X//" >'term.h' <<'END_OF_FILE'
  1762. X/* $Header: term.h,v 4.3.3.2 91/01/16 03:38:39 davison Trn $
  1763. X *
  1764. X * $Log:    term.h,v $
  1765. X * Revision 4.3.3.2  91/01/16  03:38:39  davison
  1766. X * Integrated rn patches 48-54.  Added optional prototyping.
  1767. X * 
  1768. X * Revision 4.3.3.1  90/06/20  22:40:34  davison
  1769. X * Initial Trn Release
  1770. X * 
  1771. X * Revision 4.3.2.6  90/12/10  01:32:08  sob
  1772. X * Hopefully, the rn -e -L problem is now fixed.
  1773. X * 
  1774. X * Revision 4.3.2.5  90/11/22  13:48:09  sob
  1775. X * Backed out change in Patch 48.
  1776. X * 
  1777. X * Revision 4.3.2.4  90/11/05  23:54:49  sob
  1778. X * changed maybe_eol to test when erase_screen is FALSE intstead of TRUE.
  1779. X * 
  1780. X * Revision 4.3.2.3  90/10/01  01:49:39  sob
  1781. X * Changed ospeed from short to long.
  1782. X * 
  1783. X * Revision 4.3.2.2  90/04/06  20:35:34  sob
  1784. X * Added fixes for SCO Xenix sent by ronald@robobar.co.uk.
  1785. X * 
  1786. X * Revision 4.3.2.1  89/11/28  01:54:03  sob
  1787. X * Added better support for SIGWINCH.
  1788. X * 
  1789. X * Revision 4.3.1.2  85/05/13  15:52:05  lwall
  1790. X * Declared devtty on TERMIO system.
  1791. X * 
  1792. X * Revision 4.3.1.1  85/05/10  11:41:24  lwall
  1793. X * Branch for patches.
  1794. X * 
  1795. X * Revision 4.3  85/05/01  11:51:36  lwall
  1796. X * Baseline for release with 4.3bsd.
  1797. X * 
  1798. X */
  1799. X
  1800. X#ifdef PUSHBACK
  1801. XEXT char circlebuf[PUSHSIZE];
  1802. XEXT int nextin INIT(0);
  1803. XEXT int nextout INIT(0);
  1804. X#ifdef PENDING
  1805. X#ifdef FIONREAD
  1806. XEXT long iocount INIT(0);
  1807. X#ifndef lint
  1808. X#define input_pending() (nextin!=nextout || (ioctl(0, FIONREAD, &iocount),(int)iocount))
  1809. X#else
  1810. X#define input_pending() bizarre
  1811. X#endif /* lint */
  1812. X#else /* FIONREAD */
  1813. X#ifdef RDCHK
  1814. X#define input_pending() (rdchk(0) > 0)        /* boolean only */
  1815. X#else /*  RDCHK */
  1816. Xint circfill();
  1817. XEXT int devtty INIT(0);
  1818. X#ifndef lint
  1819. X#define input_pending() (nextin!=nextout || circfill())
  1820. X#else
  1821. X#define input_pending() bizarre
  1822. X#endif /* lint */
  1823. X#endif /* RDCHK */
  1824. X#endif /* FIONREAD */
  1825. X#else /* PENDING */
  1826. X#ifndef lint
  1827. X#define input_pending() (nextin!=nextout)
  1828. X#else
  1829. X#define input_pending() bizarre
  1830. X#endif /* lint */
  1831. X#endif /* PENDING */
  1832. X#else /* PUSHBACK */
  1833. X#ifdef PENDING
  1834. X#ifdef FIONREAD    /* must have FIONREAD or O_NDELAY for input_pending() */
  1835. X#define read_tty(addr,size) read(0,addr,size)
  1836. X#ifndef lint
  1837. X#define input_pending() (ioctl(0, FIONREAD, &iocount),(int)iocount)
  1838. X#else
  1839. X#define input_pending() bizarre
  1840. X#endif /* lint */
  1841. XEXT long iocount INIT(0);
  1842. X
  1843. X#else /* FIONREAD */
  1844. X
  1845. X#ifdef RDCHK
  1846. X#define input_pending() (rdchk(0) > 0)        /* boolean only */
  1847. X#else /*  RDCHK */
  1848. X
  1849. XEXT int devtty INIT(0);
  1850. XEXT bool is_input INIT(FALSE);
  1851. XEXT char pending_ch INIT(0);
  1852. X#ifndef lint
  1853. X#define input_pending() (is_input || (is_input=read(devtty,&pending_ch,1)))
  1854. X#else
  1855. X#define input_pending() bizarre
  1856. X#endif /* lint */
  1857. X#endif /*  RDCHK */
  1858. X#endif /* FIONREAD */
  1859. X#else /* PENDING */
  1860. X#define read_tty(addr,size) read(0,addr,size)
  1861. X#define input_pending() (FALSE)
  1862. X#endif /* PENDING */
  1863. X#endif /* PUSHBACK */
  1864. X
  1865. X/* stuff wanted by terminal mode diddling routines */
  1866. X
  1867. X#ifdef TERMIO
  1868. XEXT struct termio _tty, _oldtty;
  1869. X#else
  1870. XEXT struct sgttyb _tty;
  1871. XEXT int _res_flg INIT(0);
  1872. X#endif
  1873. X
  1874. XEXT int _tty_ch INIT(2);
  1875. XEXT bool bizarre INIT(FALSE);            /* do we need to restore terminal? */
  1876. X
  1877. X/* terminal mode diddling routines */
  1878. X
  1879. X#ifdef TERMIO
  1880. X
  1881. X#define crmode() ((bizarre=1),_tty.c_lflag &=~ICANON,_tty.c_cc[VMIN] = 1,ioctl(_tty_ch,TCSETAF,&_tty))
  1882. X#define nocrmode() ((bizarre=1),_tty.c_lflag |= ICANON,_tty.c_cc[VEOF] = CEOF,stty(_tty_ch,&_tty))
  1883. X#define echo()     ((bizarre=1),_tty.c_lflag |= ECHO, ioctl(_tty_ch, TCSETA, &_tty))
  1884. X#define noecho() ((bizarre=1),_tty.c_lflag &=~ECHO, ioctl(_tty_ch, TCSETA, &_tty))
  1885. X#define nl()     ((bizarre=1),_tty.c_iflag |= ICRNL,_tty.c_oflag |= ONLCR,ioctl(_tty_ch, TCSETAW, &_tty))
  1886. X#define nonl()     ((bizarre=1),_tty.c_iflag &=~ICRNL,_tty.c_oflag &=~ONLCR,ioctl(_tty_ch, TCSETAW, &_tty))
  1887. X#define    savetty() (ioctl(_tty_ch, TCGETA, &_oldtty),ioctl(_tty_ch, TCGETA, &_tty))
  1888. X#define    resetty() ((bizarre=0),ioctl(_tty_ch, TCSETAF, &_oldtty))
  1889. X#define unflush_output()
  1890. X
  1891. X#else
  1892. X
  1893. X#define raw()     ((bizarre=1),_tty.sg_flags|=RAW, stty(_tty_ch,&_tty))
  1894. X#define noraw()     ((bizarre=1),_tty.sg_flags&=~RAW,stty(_tty_ch,&_tty))
  1895. X#define crmode() ((bizarre=1),_tty.sg_flags |= CBREAK, stty(_tty_ch,&_tty))
  1896. X#define nocrmode() ((bizarre=1),_tty.sg_flags &= ~CBREAK,stty(_tty_ch,&_tty))
  1897. X#define echo()     ((bizarre=1),_tty.sg_flags |= ECHO, stty(_tty_ch, &_tty))
  1898. X#define noecho() ((bizarre=1),_tty.sg_flags &= ~ECHO, stty(_tty_ch, &_tty))
  1899. X#define nl()     ((bizarre=1),_tty.sg_flags |= CRMOD,stty(_tty_ch, &_tty))
  1900. X#define nonl()     ((bizarre=1),_tty.sg_flags &= ~CRMOD, stty(_tty_ch, &_tty))
  1901. X#define    savetty() (gtty(_tty_ch, &_tty), _res_flg = _tty.sg_flags)
  1902. X#define    resetty() ((bizarre=0),_tty.sg_flags = _res_flg, stty(_tty_ch, &_tty))
  1903. X#ifdef LFLUSHO
  1904. X#ifndef lint
  1905. XEXT int lflusho INIT(LFLUSHO);
  1906. X#else
  1907. XEXT long lflusho INIT(LFLUSHO);
  1908. X#endif /* lint */
  1909. X#define unflush_output() (ioctl(_tty_ch,TIOCLBIC,&lflusho))
  1910. X#else
  1911. X#define unflush_output()
  1912. X#endif /* LFLUSHO */
  1913. X#endif /* TERMIO */
  1914. X
  1915. X#ifdef TIOCSTI
  1916. X#ifdef lint
  1917. X#define forceme(c) ioctl(_tty_ch,TIOCSTI,Null(long*))    /* ghad! */
  1918. X#else
  1919. X#define forceme(c) ioctl(_tty_ch,TIOCSTI,c) /* pass character in " " */
  1920. X#endif /* lint */
  1921. X#else
  1922. X#define forceme(c)
  1923. X#endif
  1924. X
  1925. X/* termcap stuff */
  1926. X
  1927. X/*
  1928. X * NOTE: if you don't have termlib you'll either have to define these strings
  1929. X *    and the tputs routine, or you'll have to redefine the macros below
  1930. X */
  1931. X
  1932. X#ifdef HAVETERMLIB
  1933. XEXT char *BC INIT(Nullch);        /* backspace character */
  1934. XEXT char *UP INIT(Nullch);        /* move cursor up one line */
  1935. XEXT char *CR INIT(Nullch);        /* get to left margin, somehow */
  1936. XEXT char *VB INIT(Nullch);        /* visible bell */
  1937. XEXT char *CL INIT(Nullch);        /* home and clear screen */
  1938. XEXT char *CE INIT(Nullch);        /* clear to end of line */
  1939. X#if defined(CLEAREOL) || defined(USETHREADS)
  1940. XEXT char *CM INIT(Nullch);        /* cursor motion */
  1941. XEXT char *HO INIT(Nullch);        /* home cursor */
  1942. X#endif
  1943. X#ifdef CLEAREOL
  1944. XEXT char *CD INIT(Nullch);        /* clear to end of display */
  1945. X#endif /* CLEAREOL */
  1946. XEXT char *SO INIT(Nullch);        /* begin standout mode */
  1947. XEXT char *SE INIT(Nullch);        /* end standout mode */
  1948. XEXT int SG INIT(0);        /* blanks left by SO and SE */
  1949. XEXT char *US INIT(Nullch);        /* start underline mode */
  1950. XEXT char *UE INIT(Nullch);        /* end underline mode */
  1951. XEXT char *UC INIT(Nullch);        /* underline a character, if that's how it's done */
  1952. XEXT int UG INIT(0);        /* blanks left by US and UE */
  1953. XEXT bool AM INIT(FALSE);        /* does terminal have automatic margins? */
  1954. XEXT bool XN INIT(FALSE);        /* does it eat 1st newline after automatic wrap? */
  1955. XEXT char PC INIT(0);        /* pad character for use by tputs() */
  1956. XEXT long ospeed INIT(0);    /* terminal output speed, for use by tputs() */
  1957. XEXT int LINES INIT(0), COLS INIT(0);    /* size of screen */
  1958. XEXT int just_a_sec INIT(960);            /* 1 sec at current baud rate */
  1959. X                    /* (number of nulls) */
  1960. X
  1961. X/* define a few handy macros */
  1962. X
  1963. X#define backspace() tputs(BC,0,putchr) FLUSH
  1964. X#define clear() tputs(CL,LINES,putchr) FLUSH
  1965. X#define erase_eol() tputs(CE,1,putchr) FLUSH
  1966. X#ifdef CLEAREOL
  1967. X#define clear_rest() tputs(CD,LINES,putchr) FLUSH
  1968. X#define maybe_eol() if(erase_screen&&can_home_clear)tputs(CE,1,putchr) FLUSH
  1969. X#endif /* CLEAREOL */
  1970. X#define underline() tputs(US,1,putchr) FLUSH
  1971. X#define un_underline() tputs(UE,1,putchr) FLUSH
  1972. X#define underchar() tputs(UC,0,putchr) FLUSH
  1973. X#define standout() tputs(SO,1,putchr) FLUSH
  1974. X#define un_standout() tputs(SE,1,putchr) FLUSH
  1975. X#define up_line() tputs(UP,1,putchr) FLUSH
  1976. X#define carriage_return() tputs(CR,1,putchr) FLUSH
  1977. X#define dingaling() tputs(VB,1,putchr) FLUSH
  1978. X#else
  1979. X  ????????        /* up to you */
  1980. X#endif
  1981. X
  1982. XEXT int page_line INIT(1);    /* line number for paging in print_line (origin 1) */
  1983. X
  1984. Xvoid    term_init ANSI((void));
  1985. Xvoid    term_set ANSI((char *));
  1986. X#ifdef PUSHBACK
  1987. Xvoid    pushchar ANSI((char));
  1988. Xvoid    mac_init ANSI((char *));
  1989. Xvoid    mac_line ANSI((char *,char *,int));
  1990. Xvoid    show_macros ANSI((void));
  1991. X#endif
  1992. Xchar    putchr ANSI((char));    /* routine for tputs to call */
  1993. Xbool    finish_command ANSI((int));
  1994. Xvoid    eat_typeahead ANSI((void));
  1995. Xvoid    settle_down ANSI((void));
  1996. X#ifndef read_tty
  1997. X    int        read_tty ANSI((char *,int));
  1998. X#endif
  1999. Xvoid    underprint ANSI((char *));
  2000. X#ifdef NOFIREWORKS
  2001. X    void    no_sofire ANSI((void));
  2002. X    void    no_ulfire ANSI((void));
  2003. X#endif
  2004. Xvoid    getcmd ANSI((char *));
  2005. Xint    get_anything ANSI((void));
  2006. Xvoid    in_char ANSI((char *,char));
  2007. Xint    print_lines ANSI((char *,int));
  2008. Xvoid    page_init ANSI((void));
  2009. Xvoid    pad ANSI((int));
  2010. Xvoid    printcmd ANSI((void));
  2011. Xvoid    rubout ANSI((void));
  2012. Xvoid    reprint ANSI((void));
  2013. X#if defined(CLEAREOL) || defined(USETHREADS)
  2014. Xvoid    home_cursor ANSI((void));
  2015. X#endif
  2016. X#ifdef USETHREADS
  2017. Xvoid    goto_line ANSI((int,int));
  2018. X#endif
  2019. X#ifdef SIGWINCH
  2020. Xint    winch_catcher ANSI((void));
  2021. X#endif /* SIGWINCH */
  2022. END_OF_FILE
  2023.   if test 8474 -ne `wc -c <'term.h'`; then
  2024.     echo shar: \"'term.h'\" unpacked with wrong size!
  2025.   fi
  2026.   # end of 'term.h'
  2027. fi
  2028. if test -f 'util.c' -a "${1}" != "-c" ; then 
  2029.   echo shar: Will not clobber existing file \"'util.c'\"
  2030. else
  2031.   echo shar: Extracting \"'util.c'\" \(10588 characters\)
  2032.   sed "s/^X//" >'util.c' <<'END_OF_FILE'
  2033. X/* $Header: util.c,v 4.3.3.3 91/01/16 03:41:50 davison Trn $
  2034. X *
  2035. X * $Log:    util.c,v $
  2036. X * Revision 4.3.3.3  91/01/16  03:41:50  davison
  2037. X * Integrated rn patches 48-54.
  2038. X * 
  2039. X * Revision 4.3.3.2  90/08/20  16:51:44  davison
  2040. X * Fixed getcwd call to not overflow any buffers.
  2041. X * 
  2042. X * Revision 4.3.3.1  90/07/21  20:34:10  davison
  2043. X * Initial Trn Release
  2044. X * 
  2045. X * Revision 4.3.2.8  90/11/22  13:54:06  sob
  2046. X * Made changes to keep more preprocessors happy.
  2047. X * 
  2048. X * Revision 4.3.2.7  90/10/01  01:52:18  sob
  2049. X * Altered the preprocessor defines on GETWD/GETCWD per suggestion by
  2050. X * rsm@math.arizona.edu.
  2051. X * 
  2052. X * Revision 4.3.2.6  90/04/23  00:24:42  sob
  2053. X * A bit of clean up.
  2054. X * 
  2055. X * Revision 4.3.2.5  90/03/17  21:34:21  sob
  2056. X * Reworked VOIDSIG into SIGRET.
  2057. X * 
  2058. X * Revision 4.3.2.4  89/12/14  23:58:54  sob
  2059. X * Fixed small bug reported by fletcher@cs.utexas.edu in getwd().
  2060. X * 
  2061. X * Revision 4.3.2.3  89/11/08  04:47:11  sob
  2062. X * Added VOIDSIG handling for SunOS 4.X
  2063. X * 
  2064. X * Revision 4.3.2.2  89/11/07  23:19:35  sob
  2065. X * Bug fixes for SIGSTP problems
  2066. X * 
  2067. X * Revision 4.3.2.1  89/11/06  01:03:21  sob
  2068. X * Added RRN support from NNTP 1.5
  2069. X * 
  2070. X * Revision 4.3.1.2  85/05/15  14:44:27  lwall
  2071. X * Last arg of execl changed from 0 to Nullch [(char*)0].
  2072. X * 
  2073. X * Revision 4.3.1.1  85/05/10  11:41:30  lwall
  2074. X * Branch for patches.
  2075. X * 
  2076. X * Revision 4.3  85/05/01  11:51:44  lwall
  2077. X * Baseline for release with 4.3bsd.
  2078. X * 
  2079. X */
  2080. X
  2081. X#include "EXTERN.h"
  2082. X#include "common.h"
  2083. X#include "final.h"
  2084. X#include "ndir.h"
  2085. X#include "INTERN.h"
  2086. X#include "util.h"
  2087. X
  2088. Xvoid
  2089. Xutil_init()
  2090. X{
  2091. X    ;
  2092. X}
  2093. X    
  2094. X/* fork and exec a shell command */
  2095. X
  2096. Xint
  2097. Xdoshell(shl,s)
  2098. Xchar *s, *shl;
  2099. X{
  2100. X    int status, pid, w;
  2101. X    char *shell;
  2102. X
  2103. X#ifdef SIGTSTP
  2104. X    sigset(SIGTSTP,SIG_DFL);
  2105. X    sigset(SIGTTOU,SIG_DFL);
  2106. X    sigset(SIGTTIN,SIG_DFL);
  2107. X#endif
  2108. X    if (shl != Nullch)
  2109. X    shell = shl;
  2110. X    else if ((shell = getenv("SHELL")) == Nullch || !*shell)
  2111. X    shell = PREFSHELL;
  2112. X    if ((pid = vfork()) == 0) {
  2113. X#ifdef SERVER
  2114. X        int i;
  2115. X
  2116. X    /* This is necessary to keep bourne shell from puking */
  2117. X
  2118. X        for (i = 3; i < 10; ++i)
  2119. X                close(i);
  2120. X#endif /* SERVER */
  2121. X
  2122. X    if (*s)
  2123. X        execl(shell, shell, "-c", s, Nullch);
  2124. X    else
  2125. X        execl(shell, shell, Nullch, Nullch, Nullch);
  2126. X    _exit(127);
  2127. X    }
  2128. X    signal(SIGINT, SIG_IGN);
  2129. X#ifdef SIGQUIT
  2130. X    signal(SIGQUIT, SIG_IGN);
  2131. X#endif
  2132. X    waiting = TRUE;
  2133. X    while ((w = wait(&status)) != pid && w != -1)
  2134. X    ;
  2135. X    if (w == -1)
  2136. X    status = -1;
  2137. X    waiting = FALSE;
  2138. X    sigset(SIGINT, int_catcher);    /* always catch interrupts */
  2139. X#ifdef SIGQUIT
  2140. X    signal(SIGQUIT, SIG_DFL);
  2141. X#endif
  2142. X#ifdef SIGTSTP
  2143. X    sigset(SIGTSTP,stop_catcher);
  2144. X    sigset(SIGTTOU,stop_catcher);
  2145. X    sigset(SIGTTIN,stop_catcher);
  2146. X#endif
  2147. X    return status;
  2148. X}
  2149. X
  2150. Xstatic char nomem[] = "rn: out of memory!\n";
  2151. X
  2152. X/* paranoid version of malloc */
  2153. X
  2154. Xchar *
  2155. Xsafemalloc(size)
  2156. XMEM_SIZE size;
  2157. X{
  2158. X    char *ptr;
  2159. X    char *malloc();
  2160. X
  2161. X    ptr = malloc(size ? size : (MEM_SIZE)1);
  2162. X    if (ptr != Nullch)
  2163. X    return ptr;
  2164. X    else {
  2165. X    fputs(nomem,stdout) FLUSH;
  2166. X    sig_catcher(0);
  2167. X    }
  2168. X    /*NOTREACHED*/
  2169. X}
  2170. X
  2171. X/* paranoid version of realloc */
  2172. X
  2173. Xchar *
  2174. Xsaferealloc(where,size)
  2175. Xchar *where;
  2176. XMEM_SIZE size;
  2177. X{
  2178. X    char *ptr;
  2179. X    char *realloc();
  2180. X
  2181. X    ptr = realloc(where,size?size:1);    /* realloc(0) is NASTY on our system */
  2182. X    if (ptr != Nullch)
  2183. X    return ptr;
  2184. X    else {
  2185. X    fputs(nomem,stdout) FLUSH;
  2186. X    sig_catcher(0);
  2187. X    }
  2188. X    /*NOTREACHED*/
  2189. X}
  2190. X
  2191. X/* safe version of string copy */
  2192. X
  2193. Xchar *
  2194. Xsafecpy(to,from,len)
  2195. Xchar *to;
  2196. Xregister char *from;
  2197. Xregister int len;
  2198. X{
  2199. X    register char *dest = to;
  2200. X
  2201. X    if (from != Nullch) 
  2202. X    for (len--; len && (*dest++ = *from++); len--) ;
  2203. X    *dest = '\0';
  2204. X    return to;
  2205. X}
  2206. X
  2207. X/* safe version of string concatenate, with \n deletion and space padding */
  2208. X
  2209. Xchar *
  2210. Xsafecat(to,from,len)
  2211. Xchar *to;
  2212. Xregister char *from;
  2213. Xregister int len;
  2214. X{
  2215. X    register char *dest = to;
  2216. X
  2217. X    len--;                /* leave room for null */
  2218. X    if (*dest) {
  2219. X    while (len && *dest++) len--;
  2220. X    if (len) {
  2221. X        len--;
  2222. X        *(dest-1) = ' ';
  2223. X    }
  2224. X    }
  2225. X    if (from != Nullch)
  2226. X    while (len && (*dest++ = *from++)) len--;
  2227. X    if (len)
  2228. X    dest--;
  2229. X    if (*(dest-1) == '\n')
  2230. X    dest--;
  2231. X    *dest = '\0';
  2232. X    return to;
  2233. X}
  2234. X
  2235. X/* copy a string up to some (non-backslashed) delimiter, if any */
  2236. X
  2237. Xchar *
  2238. Xcpytill(to,from,delim)
  2239. Xregister char *to, *from;
  2240. Xregister int delim;
  2241. X{
  2242. X    for (; *from; from++,to++) {
  2243. X    if (*from == '\\' && from[1] == delim)
  2244. X        from++;
  2245. X    else if (*from == delim)
  2246. X        break;
  2247. X    *to = *from;
  2248. X    }
  2249. X    *to = '\0';
  2250. X    return from;
  2251. X}
  2252. X
  2253. X/* return ptr to little string in big string, NULL if not found */
  2254. X
  2255. Xchar *
  2256. Xinstr(big, little)
  2257. Xchar *big, *little;
  2258. X
  2259. X{
  2260. X    register char *t, *s, *x;
  2261. X
  2262. X    for (t = big; *t; t++) {
  2263. X    for (x=t,s=little; *s; x++,s++) {
  2264. X        if (!*x)
  2265. X        return Nullch;
  2266. X        if (*s != *x)
  2267. X        break;
  2268. X    }
  2269. X    if (!*s)
  2270. X        return t;
  2271. X    }
  2272. X    return Nullch;
  2273. X}
  2274. X
  2275. X/* effective access */
  2276. X
  2277. X#ifdef SETUIDGID
  2278. Xint
  2279. Xeaccess(filename, mod)
  2280. Xchar *filename;
  2281. Xint mod;
  2282. X{
  2283. X    int protection, euid;
  2284. X    
  2285. X    mod &= 7;                /* remove extraneous garbage */
  2286. X    if (stat(filename, &filestat) < 0)
  2287. X    return -1;
  2288. X    euid = geteuid();
  2289. X    if (euid == ROOTID)
  2290. X    return 0;
  2291. X    protection = 7 & (filestat.st_mode >>
  2292. X      (filestat.st_uid == euid ? 6 :
  2293. X        (filestat.st_gid == getegid() ? 3 : 0)
  2294. X      ));
  2295. X    if ((mod & protection) == mod)
  2296. X    return 0;
  2297. X    errno = EACCES;
  2298. X    return -1;
  2299. X}
  2300. X#endif
  2301. X
  2302. X/*
  2303. X * Get working directory
  2304. X */
  2305. X#ifndef GETWD
  2306. X#ifdef GETCWD
  2307. Xchar *
  2308. Xgetwd(np)
  2309. Xchar *np;
  2310. X{
  2311. X    char * name;
  2312. X    extern char * getcwd();
  2313. X    name = getcwd(np,512);
  2314. X    return(name);
  2315. X}
  2316. X#else
  2317. Xchar *
  2318. Xgetwd(np)            /* shorter but slower */
  2319. Xchar *np;
  2320. X{
  2321. X    FILE *popen();
  2322. X    FILE *pipefp = popen("/bin/pwd","r");
  2323. X
  2324. X    if (pipefp == Nullfp) {
  2325. X    printf("Can't run /bin/pwd\n") FLUSH;
  2326. X    finalize(1);
  2327. X    }
  2328. X    fgets(np,512,pipefp);
  2329. X    np[strlen(np)-1] = '\0';    /* wipe out newline */
  2330. X    pclose(pipefp);
  2331. X    return np;
  2332. X}
  2333. X#endif
  2334. X#endif
  2335. X/* just like fgets but will make bigger buffer as necessary */
  2336. X
  2337. Xchar *
  2338. Xget_a_line(original_buffer,buffer_length,fp)
  2339. Xchar *original_buffer;
  2340. Xregister int buffer_length;
  2341. XFILE *fp;
  2342. X{
  2343. X    register int bufix = 0;
  2344. X    register int nextch;
  2345. X    register char *some_buffer_or_other = original_buffer;
  2346. X
  2347. X    do {
  2348. X    if (bufix >= buffer_length) {
  2349. X        buffer_length *= 2;
  2350. X        if (some_buffer_or_other == original_buffer) {
  2351. X                    /* currently static? */
  2352. X        some_buffer_or_other = safemalloc((MEM_SIZE)buffer_length+1);
  2353. X        strncpy(some_buffer_or_other,original_buffer,buffer_length/2);
  2354. X                    /* so we must copy it */
  2355. X        }
  2356. X        else {            /* just grow in place, if possible */
  2357. X        some_buffer_or_other = saferealloc(some_buffer_or_other,
  2358. X            (MEM_SIZE)buffer_length+1);
  2359. X        }
  2360. X    }
  2361. X    if ((nextch = getc(fp)) == EOF)
  2362. X        return Nullch;
  2363. X    some_buffer_or_other[bufix++] = (char) nextch;
  2364. X    } while (nextch && nextch != '\n');
  2365. X    some_buffer_or_other[bufix] = '\0';
  2366. X    len_last_line_got = bufix;
  2367. X    return some_buffer_or_other;
  2368. X}
  2369. X
  2370. X/* copy a string to a safe spot */
  2371. X
  2372. Xchar *
  2373. Xsavestr(str)
  2374. Xchar *str;
  2375. X{
  2376. X    register char *newaddr = safemalloc((MEM_SIZE)(strlen(str)+1));
  2377. X
  2378. X    strcpy(newaddr,str);
  2379. X    return newaddr;
  2380. X}
  2381. X
  2382. Xint
  2383. Xmakedir(dirname,nametype)
  2384. Xregister char *dirname;
  2385. Xint nametype;
  2386. X{
  2387. X#ifdef MAKEDIR
  2388. X    register char *end;
  2389. X    register char *s;
  2390. X    char tmpbuf[1024];
  2391. X    register char *tbptr = tmpbuf+5;
  2392. X
  2393. X    for (end = dirname; *end; end++) ;    /* find the end */
  2394. X    if (nametype == MD_FILE) {        /* not to create last component? */
  2395. X    for (--end; end != dirname && *end != '/'; --end) ;
  2396. X    if (*end != '/')
  2397. X        return 0;            /* nothing to make */
  2398. X    *end = '\0';            /* isolate file name */
  2399. X    }
  2400. X    strcpy(tmpbuf,"mkdir");
  2401. X
  2402. X    s = end;
  2403. X    for (;;) {
  2404. X    if (stat(dirname,&filestat) >= 0 && (filestat.st_mode & S_IFDIR)) {
  2405. X                    /* does this much exist as a dir? */
  2406. X        *s = '/';            /* mark this as existing */
  2407. X        break;
  2408. X    }
  2409. X    s = rindex(dirname,'/');    /* shorten name */
  2410. X    if (!s)                /* relative path! */
  2411. X        break;            /* hope they know what they are doing */
  2412. X    *s = '\0';            /* mark as not existing */
  2413. X    }
  2414. X    
  2415. X    for (s=dirname; s <= end; s++) {    /* this is grody but efficient */
  2416. X    if (!*s) {            /* something to make? */
  2417. X        sprintf(tbptr," %s",dirname);
  2418. X        tbptr += strlen(tbptr);    /* make it, sort of */
  2419. X        *s = '/';            /* mark it made */
  2420. X    }
  2421. X    }
  2422. X    if (nametype == MD_DIR)        /* don't need final slash unless */
  2423. X    *end = '\0';            /*  a filename follows the dir name */
  2424. X
  2425. X    return (tbptr==tmpbuf+5 ? 0 : doshell(sh,tmpbuf));
  2426. X                    /* exercise our faith */
  2427. X#else
  2428. X    sprintf(cmd_buf,"%s %s %d", filexp(DIRMAKER), dirname, nametype);
  2429. X    return doshell(sh,cmd_buf);
  2430. X#endif
  2431. X}
  2432. X
  2433. X#ifdef SETENV
  2434. Xstatic bool firstsetenv = TRUE;
  2435. Xextern char **environ;
  2436. X
  2437. Xvoid
  2438. Xsetenv(nam,val)
  2439. Xchar *nam, *val;
  2440. X{
  2441. X    register int i=envix(nam);        /* where does it go? */
  2442. X
  2443. X    if (!environ[i]) {            /* does not exist yet */
  2444. X    if (firstsetenv) {        /* need we copy environment? */
  2445. X        int j;
  2446. X#ifndef lint
  2447. X        char **tmpenv = (char**)    /* point our wand at memory */
  2448. X        safemalloc((MEM_SIZE) (i+2) * sizeof(char*));
  2449. X#else
  2450. X        char **tmpenv = Null(char **);
  2451. X#endif /* lint */
  2452. X    
  2453. X        firstsetenv = FALSE;
  2454. X        for (j=0; j<i; j++)        /* copy environment */
  2455. X        tmpenv[j] = environ[j];
  2456. X        environ = tmpenv;        /* tell exec where it is now */
  2457. X    }
  2458. X#ifndef lint
  2459. X    else
  2460. X        environ = (char**) saferealloc((char*) environ,
  2461. X        (MEM_SIZE) (i+2) * sizeof(char*));
  2462. X                    /* just expand it a bit */
  2463. X#endif /* lint */
  2464. X    environ[i+1] = Nullch;    /* make sure it's null terminated */
  2465. X    }
  2466. X    environ[i] = safemalloc((MEM_SIZE) strlen(nam) + strlen(val) + 2);
  2467. X                    /* this may or may not be in */
  2468. X                    /* the old environ structure */
  2469. X    sprintf(environ[i],"%s=%s",nam,val);/* all that work just for this */
  2470. X}
  2471. X
  2472. Xint
  2473. Xenvix(nam)
  2474. Xchar *nam;
  2475. X{
  2476. X    register int i, len = strlen(nam);
  2477. X
  2478. X    for (i = 0; environ[i]; i++) {
  2479. X    if (strnEQ(environ[i],nam,len) && environ[i][len] == '=')
  2480. X        break;            /* strnEQ must come first to avoid */
  2481. X    }                    /* potential SEGV's */
  2482. X    return i;
  2483. X}
  2484. X#endif
  2485. X
  2486. Xvoid
  2487. Xnotincl(feature)
  2488. Xchar *feature;
  2489. X{
  2490. X    printf("\nNo room for feature \"%s\" on this machine.\n",feature) FLUSH;
  2491. X}
  2492. X
  2493. Xchar *
  2494. Xgetval(nam,def)
  2495. Xchar *nam,*def;
  2496. X{
  2497. X    char *val;
  2498. X
  2499. X    if ((val = getenv(nam)) == Nullch || !*val)
  2500. X    val = def;
  2501. X    return val;
  2502. X}
  2503. X
  2504. X/* grow a static string to at least a certain length */
  2505. X
  2506. Xvoid
  2507. Xgrowstr(strptr,curlen,newlen)
  2508. Xchar **strptr;
  2509. Xint *curlen;
  2510. Xint newlen;
  2511. X{
  2512. X    if (newlen > *curlen) {        /* need more room? */
  2513. X    if (*curlen)
  2514. X        *strptr = saferealloc(*strptr,(MEM_SIZE)newlen);
  2515. X    else
  2516. X        *strptr = safemalloc((MEM_SIZE)newlen);
  2517. X    *curlen = newlen;
  2518. X    }
  2519. X}
  2520. X
  2521. Xvoid
  2522. Xsetdef(buffer,dflt)
  2523. Xchar *buffer,*dflt;
  2524. X{
  2525. X#ifdef STRICTCR
  2526. X    if (*buffer == ' ')
  2527. X#else
  2528. X    if (*buffer == ' ' || *buffer == '\n')
  2529. X#endif
  2530. X    {
  2531. X    if (*dflt == '^' && isupper(dflt[1]))
  2532. X        *buffer = Ctl(dflt[1]);
  2533. X    else
  2534. X        *buffer = *dflt;
  2535. X    }
  2536. X}
  2537. END_OF_FILE
  2538.   if test 10588 -ne `wc -c <'util.c'`; then
  2539.     echo shar: \"'util.c'\" unpacked with wrong size!
  2540.   fi
  2541.   # end of 'util.c'
  2542. fi
  2543. echo shar: End of archive 11 \(of 14\).
  2544. cp /dev/null ark11isdone
  2545. MISSING=""
  2546. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
  2547.     if test ! -f ark${I}isdone ; then
  2548.     MISSING="${MISSING} ${I}"
  2549.     fi
  2550. done
  2551. if test "${MISSING}" = "" ; then
  2552.     echo You have unpacked all 14 archives.
  2553.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2554. else
  2555.     echo You still must unpack the following archives:
  2556.     echo "        " ${MISSING}
  2557. fi
  2558. exit 0
  2559.